зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central into asynchronous plugins branch.
This commit is contained in:
Коммит
36ae808503
|
@ -120,9 +120,6 @@ export::
|
|||
ifdef ENABLE_TESTS
|
||||
# Additional makefile targets to call automated test suites
|
||||
include $(topsrcdir)/testing/testsuite-targets.mk
|
||||
else
|
||||
# OS X Universal builds will want to call this, so stub it out
|
||||
package-tests:
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -73,10 +73,10 @@
|
|||
var jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
var tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
|
||||
var url = rootDir + "/scroll.html#link1";
|
||||
var url = rootDir + "scroll.html#link1";
|
||||
var tabBrowser = document.getElementById("tabBrowser");
|
||||
tabBrowser.loadURI(url);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
}
|
||||
|
||||
var rootDir = getRootDirectory(window.location.href);
|
||||
var href = rootDir.path + "/foo";
|
||||
var href = rootDir.path + "foo";
|
||||
|
||||
// roles that can't live as nsHTMLLinkAccessibles
|
||||
testValue("aria_menuitem_link", "");
|
||||
|
|
|
@ -147,7 +147,7 @@ toolbar[mode="icons"] > #reload-button[displaystop] {
|
|||
}
|
||||
|
||||
#urlbar-progress {
|
||||
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter");
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-progress");
|
||||
}
|
||||
|
||||
/* Some child nodes want to be ordered based on the locale's direction, while
|
||||
|
|
|
@ -355,7 +355,7 @@ function test9()
|
|||
gBrowser.removeTab(tab, {animate: false});
|
||||
|
||||
// Next test
|
||||
executeSoon(finish);
|
||||
executeSoon(test10);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -372,3 +372,38 @@ function test9()
|
|||
|
||||
tab.linkedBrowser.loadURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this test, we check that the author defined error message is shown.
|
||||
*/
|
||||
function test10()
|
||||
{
|
||||
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input x-moz-errormessage='foo' required id='i'><input id='s' type='submit'></form>";
|
||||
let tab = gBrowser.addTab();
|
||||
|
||||
gInvalidFormPopup.addEventListener("popupshown", function() {
|
||||
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(doc.activeElement, doc.getElementById('i'),
|
||||
"First invalid element should be focused");
|
||||
|
||||
checkPopupShow();
|
||||
|
||||
is(gInvalidFormPopup.firstChild.nodeValue, "foo",
|
||||
"The panel should show the author defined error message");
|
||||
|
||||
// Clean-up and next test.
|
||||
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
|
||||
executeSoon(finish);
|
||||
}, false);
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
gBrowser.contentDocument.getElementById('s').click();
|
||||
}, true);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ function test()
|
|||
// Now run the tests again and then close C.
|
||||
// The test results does not matter, all this is just to exercise some code to
|
||||
// catch assertions or crashes.
|
||||
var uri = "chrome://mochikit/content/browser/" +
|
||||
"browser/base/content/test/browser_tab_dragdrop2_frame1.xul";
|
||||
var chromeroot = getRootDirectory(gTestPath);
|
||||
var uri = chromeroot + "browser_tab_dragdrop2_frame1.xul";
|
||||
let window_B = openDialog(location, "_blank", "chrome,all,dialog=no,left=200,top=200,width=200,height=200", uri);
|
||||
window_B.addEventListener("load", function(aEvent) {
|
||||
window_B.removeEventListener("load", arguments.callee, false);
|
||||
|
|
|
@ -951,4 +951,16 @@
|
|||
]]></constructor>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="urlbar-progress" extends="chrome://global/content/bindings/progressmeter.xml#progressmeter">
|
||||
<handlers>
|
||||
<handler event="transitionend"><![CDATA[
|
||||
if (this.hasAttribute("slideback") || this.value > 0)
|
||||
this.removeAttribute("slideback");
|
||||
else
|
||||
this.setAttribute("slideback", true);
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
|
|
|
@ -43,9 +43,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_pane_visibility,
|
||||
|
|
|
@ -43,9 +43,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_historymode_retention("remember", undefined),
|
||||
|
|
|
@ -42,9 +42,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("rememberHistory", "remember"),
|
||||
|
|
|
@ -42,9 +42,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
|
|
|
@ -42,9 +42,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_locbar_suggestion_retention(-1, undefined),
|
||||
|
|
|
@ -42,9 +42,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_privatebrowsing_toggle,
|
||||
|
|
|
@ -42,9 +42,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_privatebrowsing_ui,
|
||||
|
|
|
@ -41,9 +41,9 @@ function test() {
|
|||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path;
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "/privacypane_tests.js", this);
|
||||
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
|
||||
|
||||
run_test_subset([
|
||||
// history mode should be initialized to remember
|
||||
|
|
|
@ -3539,10 +3539,15 @@ SessionStoreService.prototype = {
|
|||
function sss__resetTabRestoringState(aTab, aRestoreNextTab, aRestoreThisTab) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
|
||||
// Always delete the session history listener off the browser
|
||||
delete browser.__SS_shistoryListener;
|
||||
|
||||
if (browser.__SS_restoring) {
|
||||
// If the session history listener hasn't been detached, make sure we
|
||||
// remove it and delete the reference.
|
||||
if (browser.__SS_shistoryListener) {
|
||||
browser.webNavigation.sessionHistory.
|
||||
removeSHistoryListener(browser.__SS_shistoryListener);
|
||||
delete browser.__SS_shistoryListener;
|
||||
}
|
||||
|
||||
delete browser.__SS_restoring;
|
||||
if (aRestoreNextTab) {
|
||||
// this._tabsRestoringCount is decremented in restoreNextTab.
|
||||
|
@ -3721,8 +3726,12 @@ let gRestoreTabsProgressListener = {
|
|||
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
delete aBrowser.__SS_restoring;
|
||||
this.ss.restoreNextTab(true);
|
||||
// We need to reset the tab before starting the next restore.
|
||||
// _resetTabRestoringState will make sure we remove the session history
|
||||
// listener and will call restoreNextTab.
|
||||
let window = aBrowser.ownerDocument.defaultView;
|
||||
let tab = window.gBrowser._getTabForContentWindow(aBrowser.contentWindow);
|
||||
this.ss._resetTabRestoringState(tab, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,7 +577,7 @@ function test_reload() {
|
|||
|
||||
if (loadCount == state.windows[0].tabs.length) {
|
||||
window.gBrowser.removeTabsProgressListener(progressListener);
|
||||
runNextTest();
|
||||
test_reload2(state);
|
||||
}
|
||||
else {
|
||||
// reload the next tab
|
||||
|
@ -592,6 +592,62 @@ function test_reload() {
|
|||
}
|
||||
|
||||
|
||||
// This test shouldn't be added to tests. It will be called directly from
|
||||
// test_reload. This guarantees that we're already in a tested restored state
|
||||
// and we know what the state should be.
|
||||
function test_reload2(aState) {
|
||||
info("starting test_reload2");
|
||||
let progressListener = {
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||
test_reload2_progressCallback(aBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate a left mouse button click with no modifiers, which is what
|
||||
// Command-R, or clicking reload does.
|
||||
let fakeEvent = {
|
||||
button: 0,
|
||||
metaKey: false,
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
}
|
||||
|
||||
let loadCount = 0;
|
||||
function test_reload2_progressCallback(aBrowser) {
|
||||
loadCount++;
|
||||
|
||||
if (loadCount <= aState.windows[0].tabs.length) {
|
||||
// double check that this tab was the right one
|
||||
let expectedData = aState.windows[0].tabs[loadCount - 1].extData.uniq;
|
||||
let tab;
|
||||
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||
if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
|
||||
tab = window.gBrowser.tabs[i];
|
||||
}
|
||||
is(ss.getTabValue(tab, "uniq"), expectedData,
|
||||
"test_reload2: load " + loadCount + " - correct tab was reloaded");
|
||||
|
||||
if (loadCount == aState.windows[0].tabs.length) {
|
||||
window.gBrowser.removeTabsProgressListener(progressListener);
|
||||
runNextTest();
|
||||
}
|
||||
else {
|
||||
// reload the next tab
|
||||
window.gBrowser.selectTabAtIndex(loadCount);
|
||||
BrowserReloadOrDuplicate(fakeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.gBrowser.addTabsProgressListener(progressListener);
|
||||
BrowserReloadOrDuplicate(fakeEvent);
|
||||
}
|
||||
|
||||
|
||||
function countTabs() {
|
||||
let needsRestore = 0,
|
||||
isRestoring = 0,
|
||||
|
|
|
@ -964,9 +964,18 @@ toolbar[iconsize="small"] #sync-button[status="active"] {
|
|||
background-color: transparent;
|
||||
}
|
||||
|
||||
.tab-progress[busy][stalled][value="0"],
|
||||
#urlbar-progress[busy][stalled][value="0"] {
|
||||
/* TODO: add connecting state (bug 596812) */
|
||||
#urlbar-progress[value="0"] > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
|
||||
background-size: 10%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
-moz-transition-property: background-position;
|
||||
-moz-transition-duration: 2s;
|
||||
-moz-transition-timing-function: linear;
|
||||
}
|
||||
|
||||
#urlbar-progress[value="0"][slideback] > .progress-remainder {
|
||||
background-position: left;
|
||||
}
|
||||
|
||||
.tab-progress > .progress-bar,
|
||||
|
|
|
@ -912,9 +912,18 @@ toolbar[mode="icons"] #zoom-in-button {
|
|||
margin: -2px 0 -1px;
|
||||
}
|
||||
|
||||
.tab-progress[busy][stalled][value="0"],
|
||||
#urlbar-progress[busy][stalled][value="0"] {
|
||||
/* TODO: add connecting state (bug 596812) */
|
||||
#urlbar-progress[value="0"] > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
|
||||
background-size: 10%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
-moz-transition-property: background-position;
|
||||
-moz-transition-duration: 2s;
|
||||
-moz-transition-timing-function: linear;
|
||||
}
|
||||
|
||||
#urlbar-progress[value="0"][slideback] > .progress-remainder {
|
||||
background-position: left;
|
||||
}
|
||||
|
||||
.tab-progress > .progress-bar,
|
||||
|
|
|
@ -1098,9 +1098,18 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
|
|||
background-color: transparent;
|
||||
}
|
||||
|
||||
.tab-progress[busy][stalled][value="0"],
|
||||
#urlbar-progress[busy][stalled][value="0"] {
|
||||
/* TODO: add connecting state (bug 596812) */
|
||||
#urlbar-progress[value="0"] > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(left, rgba(255,255,255,0), rgb(255,255,255), rgba(255,255,255,0)) !important;
|
||||
background-size: 10%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
-moz-transition-property: background-position;
|
||||
-moz-transition-duration: 2s;
|
||||
-moz-transition-timing-function: linear;
|
||||
}
|
||||
|
||||
#urlbar-progress[value="0"][slideback] > .progress-remainder {
|
||||
background-position: left;
|
||||
}
|
||||
|
||||
.tab-progress > .progress-bar,
|
||||
|
|
|
@ -121,8 +121,8 @@ postflight_all:
|
|||
# A universal .dmg can now be produced by making in either architecture's
|
||||
# INSTALLER_DIR.
|
||||
# Now, repeat the process for the test package.
|
||||
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= package-tests
|
||||
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= package-tests
|
||||
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= CHROME_JAR= package-tests
|
||||
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= CHROME_JAR= package-tests
|
||||
rm -rf $(DIST_UNI)/test-package-stage
|
||||
# automation.py differs because it hardcodes a path to
|
||||
# dist/bin. It doesn't matter which one we use.
|
||||
|
|
|
@ -111,4 +111,12 @@ public class ASMozStub extends android.app.Service {
|
|||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public void SendToDataChannel(String strToSend)
|
||||
{
|
||||
if (runDataThrd.isAlive())
|
||||
{
|
||||
runDataThrd.SendToDataChannel(strToSend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
android:versionName="1.0" android:sharedUserId="org.mozilla.sharedID">
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
|
||||
<activity android:name=".SUTAgentAndroid"
|
||||
android:screenOrientation="nosensor"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -25,7 +26,7 @@
|
|||
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="5"/>
|
||||
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="8"/>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
|
||||
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
|
||||
|
@ -59,4 +60,9 @@
|
|||
|
||||
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
|
||||
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.SET_TIME"></uses-permission>
|
||||
|
||||
|
||||
</manifest>
|
|
@ -55,18 +55,34 @@ public class DataWorkerThread extends Thread
|
|||
private RunDataThread theParent = null;
|
||||
private Socket socket = null;
|
||||
boolean bListening = true;
|
||||
PrintWriter out = null;
|
||||
SimpleDateFormat sdf = null;
|
||||
|
||||
public DataWorkerThread(RunDataThread theParent, Socket workerSocket)
|
||||
{
|
||||
super("DataWorkerThread");
|
||||
this.theParent = theParent;
|
||||
this.socket = workerSocket;
|
||||
this.sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
bListening = false;
|
||||
}
|
||||
|
||||
public void SendString(String strToSend)
|
||||
{
|
||||
if (this.out != null)
|
||||
{
|
||||
Calendar cal = Calendar.getInstance();
|
||||
String strOut = sdf.format(cal.getTime());
|
||||
strOut += " " + strToSend + "\r\n";
|
||||
|
||||
out.write(strOut);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private String readLine(BufferedInputStream in)
|
||||
{
|
||||
|
@ -135,13 +151,12 @@ public class DataWorkerThread extends Thread
|
|||
{
|
||||
OutputStream cmdOut = socket.getOutputStream();
|
||||
InputStream cmdIn = socket.getInputStream();
|
||||
PrintWriter out = new PrintWriter(cmdOut, true);
|
||||
this.out = new PrintWriter(cmdOut, true);
|
||||
BufferedInputStream in = new BufferedInputStream(cmdIn);
|
||||
String inputLine, outputLine;
|
||||
DoCommand dc = new DoCommand(theParent.svc);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
|
||||
sRet = sdf.format(cal.getTime());
|
||||
sRet += " trace output";
|
||||
|
||||
|
|
|
@ -60,7 +60,9 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.CheckedInputStream;
|
||||
|
@ -95,6 +97,7 @@ import android.content.pm.PackageManager;
|
|||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Debug;
|
||||
import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
import android.os.SystemClock;
|
||||
|
@ -113,9 +116,9 @@ public class DoCommand {
|
|||
ContextWrapper contextWrapper = null;
|
||||
|
||||
String currentDir = "/";
|
||||
String sErrorPrefix = "##AGENT-ERROR## ";
|
||||
String sErrorPrefix = "##AGENT-WARNING## ";
|
||||
|
||||
private final String prgVersion = "SUTAgentAndroid Version 0.80";
|
||||
private final String prgVersion = "SUTAgentAndroid Version 0.85";
|
||||
|
||||
public enum Command
|
||||
{
|
||||
|
@ -128,6 +131,7 @@ public class DoCommand {
|
|||
OS ("os"),
|
||||
ID ("id"),
|
||||
UPTIME ("uptime"),
|
||||
SETTIME ("settime"),
|
||||
SYSTIME ("systime"),
|
||||
SCREEN ("screen"),
|
||||
MEMORY ("memory"),
|
||||
|
@ -215,10 +219,18 @@ public class DoCommand {
|
|||
strReturn = prgVersion;
|
||||
break;
|
||||
|
||||
case CLOK:
|
||||
strReturn = GetClok();
|
||||
break;
|
||||
|
||||
case UPDT:
|
||||
strReturn = StartUpdateOMatic(Argv[1], Argv[2]);
|
||||
break;
|
||||
|
||||
case SETTIME:
|
||||
strReturn = SetSystemTime(Argv[1], Argv[2], cmdOut);
|
||||
break;
|
||||
|
||||
case CWD:
|
||||
try {
|
||||
strReturn = new java.io.File(currentDir).getCanonicalPath();
|
||||
|
@ -244,7 +256,7 @@ public class DoCommand {
|
|||
if (Argc == 2)
|
||||
strReturn = GetAppRoot(Argv[1]);
|
||||
else
|
||||
strReturn = sErrorPrefix + "Wrong number of arguments for cd command!";
|
||||
strReturn = sErrorPrefix + "Wrong number of arguments for getapproot command!";
|
||||
break;
|
||||
|
||||
case TESTROOT:
|
||||
|
@ -1929,6 +1941,84 @@ public class DoCommand {
|
|||
return (sRet);
|
||||
}
|
||||
|
||||
public String SetSystemTime(String sDate, String sTime, OutputStream out)
|
||||
{
|
||||
// Debug.waitForDebugger();
|
||||
String sRet = "";
|
||||
|
||||
// Intent prgIntent = new Intent(android.provider.Settings.ACTION_DATE_SETTINGS);
|
||||
// prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// contextWrapper.startActivity(prgIntent);
|
||||
|
||||
// 2010/09/22
|
||||
// 15:41:00
|
||||
// 0123456789012345678
|
||||
|
||||
if (((sDate != null) && (sTime != null)) &&
|
||||
(sDate.contains("/") || sDate.contains(".")) &&
|
||||
(sTime.contains(":")))
|
||||
{
|
||||
int year = Integer.parseInt(sDate.substring(0,4));
|
||||
int month = Integer.parseInt(sDate.substring(5,7));
|
||||
int day = Integer.parseInt(sDate.substring(8,10));
|
||||
|
||||
int hour = Integer.parseInt(sTime.substring(0,2));
|
||||
int mins = Integer.parseInt(sTime.substring(3,5));
|
||||
int secs = Integer.parseInt(sTime.substring(6,8));
|
||||
|
||||
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
|
||||
cal.set(year, month - 1, day, hour, mins, secs);
|
||||
long lMillisecs = cal.getTime().getTime();
|
||||
|
||||
// boolean bRet = SystemClock.setCurrentTimeMillis(lMillisecs);
|
||||
String sM = Long.toString(lMillisecs);
|
||||
// long lm = 1285175618316L;
|
||||
String sTest = cal.getTime().toGMTString();
|
||||
String sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3);
|
||||
String [] theArgs = new String [3];
|
||||
|
||||
theArgs[0] = "su";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "date -u " + sMillis;
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
|
||||
outThrd.start();
|
||||
outThrd.join(10000);
|
||||
sRet = GetSystemTime();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sRet = "Invalid argument(s)";
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
public String GetClok()
|
||||
{
|
||||
long lMillisecs = System.currentTimeMillis();
|
||||
String sRet = "";
|
||||
|
||||
if (lMillisecs > 0)
|
||||
sRet = Long.toString(lMillisecs);
|
||||
|
||||
return(sRet);
|
||||
}
|
||||
|
||||
public String GetUptime()
|
||||
{
|
||||
String sRet = "";
|
||||
|
@ -2140,6 +2230,9 @@ public class DoCommand {
|
|||
|
||||
try
|
||||
{
|
||||
// Tell all of the data channels we are rebooting
|
||||
((ASMozStub)this.contextWrapper).SendToDataChannel("Rebooting ...");
|
||||
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
|
@ -2551,6 +2644,9 @@ public class DoCommand {
|
|||
"rebt - reboot device\n" +
|
||||
"inst /path/filename.apk - install the referenced apk file\n" +
|
||||
"uninst packagename - uninstall the referenced package\n" +
|
||||
"updt pkgname pkgfile - unpdate the referenced package\n" +
|
||||
"clok - the current device time expressed as the number of millisecs since epoch\n" +
|
||||
"settime date time - sets the device date and time (YYYY/MM/DD HH:MM:SS)\n" +
|
||||
"rebt - reboot device\n" +
|
||||
"quit - disconnect SUTAgent\n" +
|
||||
"exit - close SUTAgent\n" +
|
||||
|
|
|
@ -66,6 +66,19 @@ public class RunDataThread extends Thread
|
|||
{
|
||||
bListening = false;
|
||||
}
|
||||
|
||||
public void SendToDataChannel(String strToSend)
|
||||
{
|
||||
int nNumWorkers = theWorkers.size();
|
||||
for (int lcv = 0; lcv < nNumWorkers; lcv++)
|
||||
{
|
||||
if (theWorkers.get(lcv).isAlive())
|
||||
{
|
||||
theWorkers.get(lcv).SendString(strToSend);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
|
|
|
@ -65,6 +65,7 @@ import android.net.wifi.WifiManager;
|
|||
import android.net.wifi.WifiManager.WifiLock;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.PowerManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
@ -133,7 +134,9 @@ public class SUTAgentAndroid extends Activity
|
|||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
|
||||
// Debug.waitForDebugger();
|
||||
|
||||
// long lHeapSize = VMRuntime.getRuntime().getMinimumHeapSize();
|
||||
// lHeapSize = 16000000;
|
||||
// VMRuntime.getRuntime().setMinimumHeapSize(lHeapSize);
|
||||
|
|
|
@ -525,6 +525,7 @@ MOZ_ENABLE_XREMOTE = @MOZ_ENABLE_XREMOTE@
|
|||
MOZ_ENABLE_DWRITE_FONT = @MOZ_ENABLE_DWRITE_FONT@
|
||||
MOZ_ENABLE_D2D_SURFACE = @MOZ_ENABLE_D2D_SURFACE@
|
||||
MOZ_ENABLE_D3D9_LAYER = @MOZ_ENABLE_D3D9_LAYER@
|
||||
MOZ_ENABLE_D3D10_LAYER = @MOZ_ENABLE_D3D10_LAYER@
|
||||
|
||||
MOZ_GTK2_CFLAGS = @MOZ_GTK2_CFLAGS@
|
||||
MOZ_GTK2_LIBS = @MOZ_GTK2_LIBS@
|
||||
|
|
|
@ -8425,6 +8425,7 @@ if test "$MOZ_TREE_CAIRO"; then
|
|||
fi
|
||||
|
||||
AC_CHECK_HEADER(d3d9.h, MOZ_ENABLE_D3D9_LAYER=1)
|
||||
AC_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
|
||||
|
||||
AC_TRY_COMPILE([#include <ddraw.h>], [int foo = DDLOCK_WAITNOTBUSY;], HAS_DDRAW=1, HAS_DDRAW=)
|
||||
if test -z "$HAS_DDRAW"; then
|
||||
|
@ -8474,6 +8475,7 @@ if test "$MOZ_TREE_CAIRO"; then
|
|||
AC_SUBST(MOZ_ENABLE_DWRITE_FONT)
|
||||
AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
|
||||
AC_SUBST(MOZ_ENABLE_D3D9_LAYER)
|
||||
AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
|
||||
AC_SUBST(CAIRO_FT_CFLAGS)
|
||||
AC_SUBST(HAS_OGLES)
|
||||
|
||||
|
|
|
@ -587,6 +587,7 @@ GK_ATOM(mouseover, "mouseover")
|
|||
GK_ATOM(mousethrough, "mousethrough")
|
||||
GK_ATOM(mouseup, "mouseup")
|
||||
GK_ATOM(moz_opaque, "moz-opaque")
|
||||
GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
|
||||
GK_ATOM(msthemecompatible, "msthemecompatible")
|
||||
GK_ATOM(multicol, "multicol")
|
||||
GK_ATOM(multiple, "multiple")
|
||||
|
|
|
@ -44,10 +44,8 @@ class nsIFormControl;
|
|||
class nsISimpleEnumerator;
|
||||
class nsIURI;
|
||||
|
||||
#define NS_FORM_METHOD_GET 0
|
||||
#define NS_FORM_METHOD_POST 1
|
||||
#define NS_FORM_METHOD_PUT 2
|
||||
#define NS_FORM_METHOD_DELETE 3
|
||||
#define NS_FORM_METHOD_GET 0
|
||||
#define NS_FORM_METHOD_POST 1
|
||||
#define NS_FORM_ENCTYPE_URLENCODED 0
|
||||
#define NS_FORM_ENCTYPE_MULTIPART 1
|
||||
#define NS_FORM_ENCTYPE_TEXTPLAIN 2
|
||||
|
|
|
@ -39,10 +39,8 @@
|
|||
#define nsFormSubmissionConstants_h__
|
||||
|
||||
static const nsAttrValue::EnumTable kFormMethodTable[] = {
|
||||
{ "get", NS_FORM_METHOD_GET },
|
||||
{ "post", NS_FORM_METHOD_POST },
|
||||
{ "put", NS_FORM_METHOD_PUT },
|
||||
{ "delete", NS_FORM_METHOD_DELETE },
|
||||
{ "get", NS_FORM_METHOD_GET },
|
||||
{ "post", NS_FORM_METHOD_POST },
|
||||
{ 0 }
|
||||
};
|
||||
// Default method is 'get'.
|
||||
|
|
|
@ -508,19 +508,6 @@ public:
|
|||
*/
|
||||
NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Helper method for NS_IMPL_ENUM_ATTR_DEFAULT_VALUE.
|
||||
* Gets the enum value string of an attribute and using a default value if
|
||||
* the attribute is missing or the string is an invalid enum value.
|
||||
*
|
||||
* @param aType the name of the attribute.
|
||||
* @param aDefault the default value if the attribute is missing or invalid.
|
||||
* @param aResult string corresponding to the value [out].
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) GetEnumAttr(nsIAtom* aAttr,
|
||||
const char* aDefault,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Returns the current disabled state of the element.
|
||||
*/
|
||||
|
@ -714,6 +701,19 @@ protected:
|
|||
*/
|
||||
NS_HIDDEN_(nsresult) GetURIListAttr(nsIAtom* aAttr, nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Helper method for NS_IMPL_ENUM_ATTR_DEFAULT_VALUE.
|
||||
* Gets the enum value string of an attribute and using a default value if
|
||||
* the attribute is missing or the string is an invalid enum value.
|
||||
*
|
||||
* @param aType the name of the attribute.
|
||||
* @param aDefault the default value if the attribute is missing or invalid.
|
||||
* @param aResult string corresponding to the value [out].
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) GetEnumAttr(nsIAtom* aAttr,
|
||||
const char* aDefault,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Locates the nsIEditor associated with this node. In general this is
|
||||
* equivalent to GetEditorInternal(), but for designmode or contenteditable,
|
||||
|
|
|
@ -898,25 +898,11 @@ nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
|
|||
getter_AddRefs(postDataStream));
|
||||
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
||||
|
||||
nsAutoString method;
|
||||
if (originatingElement &&
|
||||
originatingElement->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::formmethod)) {
|
||||
if (!originatingElement->IsHTML()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
static_cast<nsGenericHTMLElement*>(originatingElement)->
|
||||
GetEnumAttr(nsGkAtoms::formmethod, kFormDefaultMethod->tag, method);
|
||||
} else {
|
||||
GetEnumAttr(nsGkAtoms::method, kFormDefaultMethod->tag, method);
|
||||
}
|
||||
|
||||
rv = linkHandler->OnLinkClickSync(this, actionURI,
|
||||
target.get(),
|
||||
postDataStream, nsnull,
|
||||
getter_AddRefs(docShell),
|
||||
getter_AddRefs(mSubmittingRequest),
|
||||
NS_LossyConvertUTF16toASCII(method).get());
|
||||
getter_AddRefs(mSubmittingRequest));
|
||||
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,16 @@ nsIConstraintValidation::GetValidationMessage(nsAString& aValidationMessage)
|
|||
aValidationMessage.Truncate();
|
||||
|
||||
if (IsCandidateForConstraintValidation() && !IsValid()) {
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR)) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(this);
|
||||
NS_ASSERTION(content, "This class should be inherited by HTML elements only!");
|
||||
|
||||
nsAutoString authorMessage;
|
||||
content->GetAttr(kNameSpaceID_None, nsGkAtoms::x_moz_errormessage,
|
||||
authorMessage);
|
||||
|
||||
if (!authorMessage.IsEmpty()) {
|
||||
aValidationMessage.Assign(authorMessage);
|
||||
} else if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR)) {
|
||||
aValidationMessage.Assign(mCustomValidity);
|
||||
} else if (GetValidityState(VALIDITY_STATE_TOO_LONG)) {
|
||||
GetValidationMessage(aValidationMessage, VALIDITY_STATE_TOO_LONG);
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
// Redirect to another domain.
|
||||
// Using 307 to keep the method.
|
||||
response.setStatusLine(null, 307, "Temp");
|
||||
response.setHeader("Location",
|
||||
"http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs");
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
// Send the HTTP method.
|
||||
response.write(request.method);
|
||||
}
|
|
@ -212,11 +212,6 @@ _TEST_FILES = \
|
|||
test_bug590353-1.html \
|
||||
test_bug590353-2.html \
|
||||
test_bug593689.html \
|
||||
test_bug583288-1.html \
|
||||
test_bug583288-2.html \
|
||||
test_bug583288-3.html \
|
||||
583288_submit_server.sjs \
|
||||
583288_redirect_server.sjs \
|
||||
test_bug555840.html \
|
||||
test_bug561636.html \
|
||||
test_bug556013.html \
|
||||
|
@ -235,6 +230,7 @@ _TEST_FILES = \
|
|||
test_bug557087-4.html \
|
||||
test_bug557087-5.html \
|
||||
test_bug557087-6.html \
|
||||
test_bug600155.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 583288</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload='runTests();'>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
|
||||
<p id="display"></p>
|
||||
<style>
|
||||
iframe { width: 70px; height: 40px;}
|
||||
</style>
|
||||
<!--<div id="content" style="display: none">-->
|
||||
<div id="content">
|
||||
<iframe name='get' id='get'></iframe>
|
||||
<iframe name='post' id='post'></iframe>
|
||||
<iframe name='put' id='put'></iframe>
|
||||
<iframe name='del' id='del'></iframe>
|
||||
<iframe name='get2' id='get2'></iframe>
|
||||
<iframe name='post2' id='post2'></iframe>
|
||||
<iframe name='put2' id='put2'></iframe>
|
||||
<iframe name='del2' id='del2'></iframe>
|
||||
|
||||
<form action="583288_submit_server.sjs" target='get' method='get'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs" target='post' method='post'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs" target='put' method='put'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs" target='del' method='delete'>
|
||||
</form>
|
||||
|
||||
<form action="583288_submit_server.sjs">
|
||||
<input type='submit' id='iget' value='get' formtarget='get2' formmethod='get'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs">
|
||||
<input type='submit' id='ipost' value='post' formtarget='post2' formmethod='post'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs">
|
||||
<input type='submit' id='iput' value='put' formtarget='put2' formmethod='put'>
|
||||
</form>
|
||||
<form action="583288_submit_server.sjs">
|
||||
<input type='submit' id='idel' value='delete' formtarget='del2' formmethod='delete'>
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 583288 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gTestResults = {
|
||||
get: "GET",
|
||||
get2: "GET",
|
||||
post: "POST",
|
||||
post2: "POST",
|
||||
put: "PUT",
|
||||
put2: "PUT",
|
||||
del: "DELETE",
|
||||
del2: "DELETE",
|
||||
};
|
||||
|
||||
var gPendingLoad = 0; // Has to be set after depending on the frames number.
|
||||
|
||||
function runTests()
|
||||
{
|
||||
// We add a load event for the frames which will be called when the forms
|
||||
// will be submitted.
|
||||
var frames = [ document.getElementById('get'),
|
||||
document.getElementById('get2'),
|
||||
document.getElementById('post'),
|
||||
document.getElementById('post2'),
|
||||
document.getElementById('put'),
|
||||
document.getElementById('put2'),
|
||||
document.getElementById('del'),
|
||||
document.getElementById('del2'),
|
||||
];
|
||||
gPendingLoad = frames.length;
|
||||
|
||||
for (var i=0; i<frames.length; ++i) {
|
||||
frames[i].setAttribute('onload', "frameLoaded(this);");
|
||||
}
|
||||
|
||||
// The four first forms can be submitted with .submit().
|
||||
for (var i=0; i<4; ++i) {
|
||||
document.forms[i].submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* We are going to focus each element before interacting with them so we are
|
||||
* sure they will be visible in the iframe.
|
||||
* Considering we are using synthesizeKey that may be not required.
|
||||
*
|
||||
* Focusing the first element (id='iget') is launching the tests.
|
||||
*/
|
||||
document.getElementById('iget').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('ipost').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('ipost').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('iput').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('iput').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
document.getElementById('idel').focus();
|
||||
}, false);
|
||||
|
||||
document.getElementById('idel').addEventListener('focus', function(aEvent) {
|
||||
aEvent.target.removeEventListener('focus', arguments.callee, false);
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
}, false);
|
||||
|
||||
document.getElementById('iget').focus();
|
||||
}
|
||||
|
||||
function frameLoaded(aFrame) {
|
||||
// Check if formaction/action has the correct behavior.
|
||||
is(aFrame.contentDocument.documentElement.textContent, gTestResults[aFrame.name],
|
||||
"the method used during the form submission should be " +
|
||||
gTestResults[aFrame.name]);
|
||||
|
||||
if (--gPendingLoad == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,99 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 583288</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload='runTests();'>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
|
||||
<p id="display"></p>
|
||||
<style>
|
||||
iframe { width: 70px; height: 40px;}
|
||||
</style>
|
||||
<!--<div id="content" style="display: none">-->
|
||||
<div id="content">
|
||||
<iframe name='get' id='get'></iframe>
|
||||
<iframe name='post' id='post'></iframe>
|
||||
<iframe name='put' id='put'></iframe>
|
||||
<iframe name='del' id='del'></iframe>
|
||||
|
||||
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='get' method='get'>
|
||||
</form>
|
||||
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='post' method='post'>
|
||||
</form>
|
||||
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='put' method='put'>
|
||||
</form>
|
||||
<form action="http://example.org:80/tests/content/html/content/test/583288_submit_server.sjs" target='del' method='delete'>
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 583288 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gLoaded = 0;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
// We add a load event for the frames which will be called when the forms
|
||||
// will be submitted.
|
||||
var frames = [ document.getElementById('get'),
|
||||
document.getElementById('post'),
|
||||
document.getElementById('put'),
|
||||
document.getElementById('del'),
|
||||
];
|
||||
|
||||
for (var i=0; i<2; ++i) {
|
||||
frames[i].setAttribute('onload', "frameShouldLoad();");
|
||||
}
|
||||
for (var i=2; i<4; ++i) {
|
||||
frames[i].setAttribute('onload', "frameShouldNotLoad();");
|
||||
}
|
||||
|
||||
// The four forms can be submitted with .submit().
|
||||
// Submitting those which should be blocked so we can considering if the the
|
||||
// last ones are submitted, that means the firsts were blocked.
|
||||
for (var i=3; i>=0; --i) {
|
||||
document.forms[i].submit();
|
||||
}
|
||||
|
||||
// After the two first succefull submissions, we are going to stop the test.
|
||||
// The expected successfull submissions have been requested at the end so we
|
||||
// expect them at the end. So if the two firsts ones didn't show up, we are
|
||||
// assuming they have been blocked.
|
||||
// Unfortunately, it doesn't sound like there is a better way to test that.
|
||||
// The worst thing that can happen here is to have a random green (if the
|
||||
// first two submissions were not blocked but came after the last two).
|
||||
}
|
||||
|
||||
function frameShouldLoad() {
|
||||
ok(true, "The form submission should succeed.");
|
||||
if (++gLoaded == 2) {
|
||||
finished();
|
||||
}
|
||||
}
|
||||
|
||||
function frameShouldNotLoad() {
|
||||
ok(false, "The form submission should have been blocked");
|
||||
if (++gLoaded == 2) {
|
||||
finished();
|
||||
}
|
||||
}
|
||||
|
||||
function finished()
|
||||
{
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,85 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=583288
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 583288</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload='runTests();'>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583288">Mozilla Bug 583288</a>
|
||||
<p id="display"></p>
|
||||
<style>
|
||||
iframe { width: 70px; height: 40px;}
|
||||
</style>
|
||||
<!--<div id="content" style="display: none">-->
|
||||
<div id="content">
|
||||
<iframe name='get' id='get'></iframe>
|
||||
<iframe name='post' id='post'></iframe>
|
||||
<iframe name='put' id='put'></iframe>
|
||||
<iframe name='del' id='del'></iframe>
|
||||
|
||||
<form action="583288_redirect_server.sjs" target='get' method='get'>
|
||||
</form>
|
||||
<form action="583288_redirect_server.sjs" target='post' method='post'>
|
||||
</form>
|
||||
<form action="583288_redirect_server.sjs" target='put' method='put'>
|
||||
</form>
|
||||
<form action="583288_redirect_server.sjs" target='del' method='delete'>
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 583288 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gTestResults = {
|
||||
get: "GET",
|
||||
post: "POST",
|
||||
put: "",
|
||||
del: "",
|
||||
};
|
||||
|
||||
var gPendingLoad = 0; // Has to be set after depending on the frames number.
|
||||
|
||||
function runTests()
|
||||
{
|
||||
// We add a load event for the frames which will be called when the forms
|
||||
// will be submitted.
|
||||
var frames = [ document.getElementById('get'),
|
||||
document.getElementById('post'),
|
||||
document.getElementById('put'),
|
||||
document.getElementById('del'),
|
||||
];
|
||||
gPendingLoad = frames.length;
|
||||
|
||||
for (var i=0; i<gPendingLoad; ++i) {
|
||||
frames[i].setAttribute('onload', "frameLoaded(this);");
|
||||
}
|
||||
|
||||
// The four forms can be submitted with .submit().
|
||||
for (var i=0; i<4; ++i) {
|
||||
document.forms[i].submit();
|
||||
}
|
||||
}
|
||||
|
||||
function frameLoaded(aFrame) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
is(aFrame.contentDocument.documentElement.textContent, gTestResults[aFrame.name],
|
||||
"cross-origin submission with redirection should work");
|
||||
|
||||
if (--gPendingLoad == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -30,9 +30,11 @@ var methodTestData = [
|
|||
// Default value.
|
||||
[ "get" ],
|
||||
// Valid values.
|
||||
[ "get", "post", "put", "delete" ],
|
||||
[ "get", "post" ],
|
||||
// Invalid values.
|
||||
[ "", " ", "foo" ],
|
||||
// TODO values, see bug 583289 and bug 583288.
|
||||
[ "delete", "put" ],
|
||||
];
|
||||
|
||||
function checkAttribute(form, attrName, idlName, data)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=600155
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 600155</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600155">Mozilla Bug 600155</a>
|
||||
<p id="display"></p>
|
||||
<div id='content' style='display:none;'>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 600155 **/
|
||||
|
||||
var subjectForConstraintValidation = [ "button", "input", "select", "textarea" ];
|
||||
var content = document.getElementById('content');
|
||||
|
||||
for each (var eName in subjectForConstraintValidation) {
|
||||
var e = document.createElement(eName);
|
||||
content.appendChild(e);
|
||||
e.setAttribute("x-moz-errormessage", "foo");
|
||||
if ("required" in e) {
|
||||
e.required = true;
|
||||
} else {
|
||||
e.setCustomValidity("bar");
|
||||
}
|
||||
|
||||
// At this point, the element is invalid.
|
||||
is(e.validationMessage, "foo",
|
||||
"the validation message should be the author one");
|
||||
|
||||
content.removeChild(e);
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1412,8 +1412,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||
nsnull, // No SHEntry
|
||||
aFirstParty,
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull, // No nsIRequest
|
||||
nsnull); // Use default HTTP method
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -4096,7 +4095,7 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
|||
return InternalLoad(errorPageURI, nsnull, nsnull,
|
||||
INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nsnull, nsnull,
|
||||
nsnull, nsnull, LOAD_ERROR_PAGE,
|
||||
nsnull, PR_TRUE, nsnull, nsnull, nsnull);
|
||||
nsnull, PR_TRUE, nsnull, nsnull);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4160,8 +4159,7 @@ nsDocShell::Reload(PRUint32 aReloadFlags)
|
|||
nsnull, // No SHEntry
|
||||
PR_TRUE,
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull, // No nsIRequest
|
||||
nsnull); // Use default HTTP method
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
|
||||
|
||||
|
@ -5871,7 +5869,7 @@ nsDocShell::OnLocationChange(nsIWebProgress * aProgress,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
nsIChannel* aNewChannel,
|
||||
PRUint32 aRedirectFlags,
|
||||
|
@ -5880,44 +5878,13 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
|||
NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
|
||||
"Calling OnRedirectStateChange when there is no redirect");
|
||||
if (!(aStateFlags & STATE_IS_DOCUMENT))
|
||||
return NS_OK; // not a toplevel document
|
||||
return; // not a toplevel document
|
||||
|
||||
nsCOMPtr<nsIURI> oldURI, newURI;
|
||||
aOldChannel->GetURI(getter_AddRefs(oldURI));
|
||||
aNewChannel->GetURI(getter_AddRefs(newURI));
|
||||
if (!oldURI || !newURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// HTTP channel with unsafe methods should not be redirected to a cross-domain.
|
||||
if (!ChannelIsSafeHTTPMethod(aNewChannel)) {
|
||||
// This code is very similar to the code of nsSameOriginChecker in
|
||||
// nsContentUtils but we can't use nsSameOriginChecker because it
|
||||
// needs to use a channel callback (which we already use).
|
||||
// If nsSameOriginChecker happens to not use a channel callback
|
||||
// anymore, this code would be a good candidate for refactoring.
|
||||
nsCOMPtr<nsIPrincipal> oldPrincipal;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
|
||||
rv = secMan->GetChannelPrincipal(aOldChannel,
|
||||
getter_AddRefs(oldPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
NS_ASSERTION(oldPrincipal, "oldPrincipal should not be null!");
|
||||
|
||||
nsCOMPtr<nsIURI> newOriginalURI;
|
||||
aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
|
||||
|
||||
rv = oldPrincipal->CheckMayLoad(newURI, PR_FALSE);
|
||||
if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
|
||||
rv = oldPrincipal->CheckMayLoad(newOriginalURI, PR_FALSE);
|
||||
}
|
||||
|
||||
// The requested tried to be redirected, we have to cancel it.
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// Below a URI visit is saved (see AddURIVisit method doc).
|
||||
|
@ -5968,8 +5935,6 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
|||
mLoadType = LOAD_NORMAL_REPLACE;
|
||||
SetHistoryEntry(&mLSHE, nsnull);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6341,8 +6306,7 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
|
|||
nsnull, // No SHEntry
|
||||
PR_TRUE, // first party site
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull, // No nsIRequest
|
||||
nsnull); // Use default HTTP method
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
else {
|
||||
DisplayLoadError(aStatus, url, nsnull, aChannel);
|
||||
|
@ -7784,7 +7748,7 @@ public:
|
|||
return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
|
||||
nsnull, mTypeHint.get(),
|
||||
mPostData, mHeadersData, mLoadType,
|
||||
mSHEntry, mFirstParty, nsnull, nsnull, nsnull);
|
||||
mSHEntry, mFirstParty, nsnull, nsnull);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -7818,8 +7782,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
nsISHEntry * aSHEntry,
|
||||
PRBool aFirstParty,
|
||||
nsIDocShell** aDocShell,
|
||||
nsIRequest** aRequest,
|
||||
const char* aHttpMethod)
|
||||
nsIRequest** aRequest)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -8021,8 +7984,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
aSHEntry,
|
||||
aFirstParty,
|
||||
aDocShell,
|
||||
aRequest,
|
||||
aHttpMethod);
|
||||
aRequest);
|
||||
if (rv == NS_ERROR_NO_CONTENT) {
|
||||
// XXXbz except we never reach this code!
|
||||
if (isNewWindow) {
|
||||
|
@ -8457,8 +8419,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
aDocShell, getter_AddRefs(req),
|
||||
(aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
|
||||
(aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
|
||||
(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
|
||||
aHttpMethod);
|
||||
(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0);
|
||||
if (req && aRequest)
|
||||
NS_ADDREF(*aRequest = req);
|
||||
|
||||
|
@ -8539,8 +8500,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
nsIRequest ** aRequest,
|
||||
PRBool aIsNewWindowTarget,
|
||||
PRBool aBypassClassifier,
|
||||
PRBool aForceAllowCookies,
|
||||
const char* aHttpMethod)
|
||||
PRBool aForceAllowCookies)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURILoader> uriLoader;
|
||||
|
@ -8723,20 +8683,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
// Referrer is currenly only set for link clicks here.
|
||||
httpChannel->SetReferrer(aReferrerURI);
|
||||
}
|
||||
|
||||
// If a specific HTTP method has been requested, set it.
|
||||
if (aHttpMethod) {
|
||||
// Tell the cache it _has_ to open a cache entry.
|
||||
PRUint32 loadFlags;
|
||||
if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
|
||||
channel->SetLoadFlags(loadFlags | nsICachingChannel::FORCE_OPEN_CACHE_ENTRY);
|
||||
}
|
||||
|
||||
// The method name have to be correct.
|
||||
// Otherwise SetRequestMethod will return a failure.
|
||||
rv = httpChannel->SetRequestMethod(nsDependentCString(aHttpMethod));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Set the owner of the channel, but only for channels that can't
|
||||
|
@ -8787,14 +8733,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
}
|
||||
}
|
||||
|
||||
// If a specific HTTP channel has been set and it is not a safe method,
|
||||
// we should prevent cross-origin requests.
|
||||
if (aHttpMethod && ownerPrincipal && !ChannelIsSafeHTTPMethod(channel)) {
|
||||
if (NS_FAILED(ownerPrincipal->CheckMayLoad(aURI, PR_FALSE))) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
|
||||
if (scriptChannel) {
|
||||
// Allow execution against our context if the principals match
|
||||
|
@ -10006,8 +9944,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
|
|||
aEntry, // SHEntry
|
||||
PR_TRUE,
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull, // No nsIRequest
|
||||
nsnull); // Use default HTTP method
|
||||
nsnull); // No nsIRequest
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -10420,7 +10357,6 @@ NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
|
|||
return mEditorData->MakeEditable(inWaitForUriLoad);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
|
||||
{
|
||||
|
@ -10434,21 +10370,6 @@ nsDocShell::ChannelIsPost(nsIChannel* aChannel)
|
|||
return method.Equals("POST");
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsDocShell::ChannelIsSafeHTTPMethod(nsIChannel* aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
|
||||
if (!httpChannel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCAutoString method;
|
||||
httpChannel->GetRequestMethod(method);
|
||||
return method.Equals("GET") || method.Equals("POST") ||
|
||||
method.Equals("HEAD");
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
|
||||
nsIURI** aURI,
|
||||
|
@ -11379,8 +11300,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
|
|||
nsIInputStream* aPostDataStream,
|
||||
nsIInputStream* aHeadersDataStream,
|
||||
nsIDocShell** aDocShell,
|
||||
nsIRequest** aRequest,
|
||||
const char* aHttpMethod)
|
||||
nsIRequest** aRequest)
|
||||
{
|
||||
// Initialize the DocShell / Request
|
||||
if (aDocShell) {
|
||||
|
@ -11456,8 +11376,7 @@ nsDocShell::OnLinkClickSync(nsIContent *aContent,
|
|||
nsnull, // No SHEntry
|
||||
PR_TRUE, // first party site
|
||||
aDocShell, // DocShell out-param
|
||||
aRequest, // Request out-param
|
||||
aHttpMethod); // HTTP Method
|
||||
aRequest); // Request out-param
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DispatchPings(aContent, referer);
|
||||
}
|
||||
|
|
|
@ -243,8 +243,7 @@ public:
|
|||
nsIInputStream* aPostDataStream = 0,
|
||||
nsIInputStream* aHeadersDataStream = 0,
|
||||
nsIDocShell** aDocShell = 0,
|
||||
nsIRequest** aRequest = 0,
|
||||
const char* aHttpMethod = 0);
|
||||
nsIRequest** aRequest = 0);
|
||||
NS_IMETHOD OnOverLink(nsIContent* aContent,
|
||||
nsIURI* aURI,
|
||||
const PRUnichar* aTargetSpec);
|
||||
|
@ -326,8 +325,7 @@ protected:
|
|||
nsIRequest ** aRequest,
|
||||
PRBool aIsNewWindowTarget,
|
||||
PRBool aBypassClassifier,
|
||||
PRBool aForceAllowCookies,
|
||||
const char* aHttpMethod);
|
||||
PRBool aForceAllowCookies);
|
||||
NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData,
|
||||
nsIChannel * aChannel);
|
||||
virtual nsresult DoChannelLoad(nsIChannel * aChannel,
|
||||
|
@ -436,10 +434,10 @@ protected:
|
|||
|
||||
// overridden from nsDocLoader, this provides more information than the
|
||||
// normal OnStateChange with flags STATE_REDIRECTING
|
||||
virtual nsresult OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
nsIChannel* aNewChannel,
|
||||
PRUint32 aRedirectFlags,
|
||||
PRUint32 aStateFlags);
|
||||
virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
nsIChannel* aNewChannel,
|
||||
PRUint32 aRedirectFlags,
|
||||
PRUint32 aStateFlags);
|
||||
|
||||
/**
|
||||
* Helper function that determines if channel is an HTTP POST.
|
||||
|
@ -449,17 +447,7 @@ protected:
|
|||
*
|
||||
* @return True iff channel is an HTTP post.
|
||||
*/
|
||||
static bool ChannelIsPost(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Helper function that determines if the HTTP channel has a safe method
|
||||
*
|
||||
* @param aChannel The channel to test
|
||||
*
|
||||
* @return Whether the channel has a safe HTTP method.
|
||||
* @note Will return true if the channel isn't an HTTP channel.
|
||||
*/
|
||||
static bool ChannelIsSafeHTTPMethod(nsIChannel* aChannel);
|
||||
bool ChannelIsPost(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Helper function that finds the last URI and its transition flags for a
|
||||
|
|
|
@ -71,7 +71,7 @@ interface nsIPrincipal;
|
|||
interface nsIWebBrowserPrint;
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(0e1e1ee5-5baa-4e27-98af-3197d70d0304)]
|
||||
[scriptable, uuid(74470127-87eb-4f79-8293-1616fe9cb689)]
|
||||
interface nsIDocShell : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -155,10 +155,6 @@ interface nsIDocShell : nsISupports
|
|||
* @param aLoadFlags - Flags to modify load behaviour. Flags are defined
|
||||
* in nsIWebNavigation.
|
||||
* @param aSHEntry - Active Session History entry (if loading from SH)
|
||||
* @param firstParty -
|
||||
* @param aDocShell -
|
||||
* @param aRequest -
|
||||
* @param aHttpMethod - Force the HTTP channel to use a specific HTTP method
|
||||
*/
|
||||
[noscript]void internalLoad(in nsIURI aURI,
|
||||
in nsIURI aReferrer,
|
||||
|
@ -172,8 +168,7 @@ interface nsIDocShell : nsISupports
|
|||
in nsISHEntry aSHEntry,
|
||||
in boolean firstParty,
|
||||
out nsIDocShell aDocShell,
|
||||
out nsIRequest aRequest,
|
||||
in string aHttpMethod);
|
||||
out nsIRequest aRequest);
|
||||
|
||||
/**
|
||||
* Do either a history.pushState() or history.replaceState() operation,
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIConsoleService.h"
|
||||
|
||||
#include "History.h"
|
||||
#include "nsDocShellCID.h"
|
||||
|
@ -112,6 +114,59 @@ private:
|
|||
nsString mData;
|
||||
};
|
||||
|
||||
class ConsoleListener : public nsIConsoleListener
|
||||
{
|
||||
public:
|
||||
ConsoleListener(ContentChild* aChild)
|
||||
: mChild(aChild) {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONSOLELISTENER
|
||||
|
||||
private:
|
||||
ContentChild* mChild;
|
||||
friend class ContentChild;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ConsoleListener, nsIConsoleListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ConsoleListener::Observe(nsIConsoleMessage* aMessage)
|
||||
{
|
||||
if (!mChild)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
|
||||
if (scriptError) {
|
||||
nsString msg, sourceName, sourceLine;
|
||||
nsXPIDLCString category;
|
||||
PRUint32 lineNum, colNum, flags;
|
||||
|
||||
nsresult rv = scriptError->GetErrorMessage(msg);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetSourceName(sourceName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetSourceLine(sourceLine);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetCategory(getter_Copies(category));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetLineNumber(&lineNum);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetColumnNumber(&colNum);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = scriptError->GetFlags(&flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mChild->SendScriptError(msg, sourceName, sourceLine,
|
||||
lineNum, colNum, flags, category);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsXPIDLString msg;
|
||||
nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mChild->SendConsoleMessage(msg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ContentChild* ContentChild::sSingleton;
|
||||
|
||||
|
@ -146,6 +201,20 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::InitXPCOM()
|
||||
{
|
||||
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (!svc) {
|
||||
NS_WARNING("Couldn't acquire console service");
|
||||
return;
|
||||
}
|
||||
|
||||
mConsoleListener = new ConsoleListener(this);
|
||||
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
|
||||
NS_WARNING("Couldn't register console listener for child process");
|
||||
}
|
||||
|
||||
PBrowserChild*
|
||||
ContentChild::AllocPBrowser(const PRUint32& aChromeFlags)
|
||||
{
|
||||
|
@ -253,6 +322,13 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
|
|||
#endif
|
||||
|
||||
mAlertObservers.Clear();
|
||||
|
||||
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (svc) {
|
||||
svc->UnregisterListener(mConsoleListener);
|
||||
mConsoleListener->mChild = nsnull;
|
||||
}
|
||||
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "mozilla/dom/PContentChild.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsIConsoleListener.h"
|
||||
|
||||
struct ChromePackage;
|
||||
class nsIObserver;
|
||||
|
@ -54,6 +55,7 @@ namespace dom {
|
|||
|
||||
class AlertObserver;
|
||||
class PrefObserver;
|
||||
class ConsoleListener;
|
||||
|
||||
class ContentChild : public PContentChild
|
||||
{
|
||||
|
@ -64,6 +66,7 @@ public:
|
|||
bool Init(MessageLoop* aIOLoop,
|
||||
base::ProcessHandle aParentHandle,
|
||||
IPC::Channel* aChannel);
|
||||
void InitXPCOM();
|
||||
|
||||
static ContentChild* GetSingleton() {
|
||||
NS_ASSERTION(sSingleton, "not initialized");
|
||||
|
@ -124,6 +127,7 @@ private:
|
|||
|
||||
nsTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
|
||||
nsTArray<nsAutoPtr<PrefObserver> > mPrefObservers;
|
||||
nsRefPtr<ConsoleListener> mConsoleListener;
|
||||
bool mDead;
|
||||
|
||||
static ContentChild* sSingleton;
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
#include "nsIAlertsService.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsIDOMGeoGeolocation.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsConsoleMessage.h"
|
||||
|
||||
#include "mozilla/dom/ExternalHelperAppParent.h"
|
||||
|
||||
|
@ -547,5 +550,40 @@ ContentParent::HandleEvent(nsIDOMGeoPosition* postion)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvConsoleMessage(const nsString& aMessage)
|
||||
{
|
||||
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (!svc)
|
||||
return true;
|
||||
|
||||
nsRefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get()));
|
||||
svc->LogMessage(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvScriptError(const nsString& aMessage,
|
||||
const nsString& aSourceName,
|
||||
const nsString& aSourceLine,
|
||||
const PRUint32& aLineNumber,
|
||||
const PRUint32& aColNumber,
|
||||
const PRUint32& aFlags,
|
||||
const nsCString& aCategory)
|
||||
{
|
||||
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (!svc)
|
||||
return true;
|
||||
|
||||
nsCOMPtr<nsIScriptError> msg(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
nsresult rv = msg->Init(aMessage.get(), aSourceName.get(), aSourceLine.get(),
|
||||
aLineNumber, aColNumber, aFlags, aCategory.get());
|
||||
if (NS_FAILED(rv))
|
||||
return true;
|
||||
|
||||
svc->LogMessage(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -157,6 +157,15 @@ private:
|
|||
virtual bool RecvGeolocationStart();
|
||||
virtual bool RecvGeolocationStop();
|
||||
|
||||
virtual bool RecvConsoleMessage(const nsString& aMessage);
|
||||
virtual bool RecvScriptError(const nsString& aMessage,
|
||||
const nsString& aSourceName,
|
||||
const nsString& aSourceLine,
|
||||
const PRUint32& aLineNumber,
|
||||
const PRUint32& aColNumber,
|
||||
const PRUint32& aFlags,
|
||||
const nsCString& aCategory);
|
||||
|
||||
mozilla::Monitor mMonitor;
|
||||
|
||||
GeckoChildProcessHost* mSubprocess;
|
||||
|
|
|
@ -53,6 +53,7 @@ ContentProcess::Init()
|
|||
ParentHandle(),
|
||||
IOThreadChild::channel());
|
||||
mXREEmbed.Start();
|
||||
mContent.InitXPCOM();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ LOCAL_INCLUDES += \
|
|||
-I$(topsrcdir)/uriloader/exthandler \
|
||||
-I$(srcdir)/../../netwerk/base/src \
|
||||
-I$(srcdir)/../src/base \
|
||||
-I$(srcdir)/../../xpcom/base \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
|
||||
|
|
|
@ -91,6 +91,26 @@ parent:
|
|||
sync SyncMessage(nsString aMessage, nsString aJSON)
|
||||
returns (nsString[] retval);
|
||||
|
||||
/**
|
||||
* The IME sequence number (seqno) parameter is used to make sure
|
||||
* that a notification is discarded if it arrives at the chrome process
|
||||
* too late. If the notification is late and we accept it, we will have
|
||||
* an out-of-date view of the content process, which means events that we
|
||||
* dispatch based on this out-of-date view will be wrong also.
|
||||
* (see Bug 599550 and Bug 591047 comments 44, 50, and 54)
|
||||
*
|
||||
* Chrome increments seqno and includes it in each IME event sent to
|
||||
* content, and content sends its current seqno back to chrome with each
|
||||
* notification. A notification is up-to-date only if the content
|
||||
* seqno is the same as the current chrome seqno, meaning no additional
|
||||
* event was sent to content before the notification was received
|
||||
*
|
||||
* On blur, chrome returns the current seqno to content, and content
|
||||
* uses it to discard subsequent events until the content seqno and
|
||||
* chrome seqno-on-blur match again. These events, meant for the blurred
|
||||
* textfield, are discarded to prevent events going to the wrong target
|
||||
*/
|
||||
|
||||
/**
|
||||
* Notifies chrome that there is a focus change involving an editable
|
||||
* object (input, textarea, document, contentEditable. etc.)
|
||||
|
@ -98,9 +118,10 @@ parent:
|
|||
* focus PR_TRUE if editable object is receiving focus
|
||||
* PR_FALSE if losing focus
|
||||
* preference Native widget preference for IME updates
|
||||
* seqno Current seqno value on the chrome side
|
||||
*/
|
||||
sync NotifyIMEFocus(PRBool focus)
|
||||
returns (nsIMEUpdatePreference preference);
|
||||
returns (nsIMEUpdatePreference preference, PRUint32 seqno);
|
||||
|
||||
/**
|
||||
* Notifies chrome that there has been a change in text content
|
||||
|
@ -120,10 +141,11 @@ parent:
|
|||
* Notifies chrome that there has been a change in selection
|
||||
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
|
||||
*
|
||||
* seqno Current seqno value on the content side
|
||||
* anchor Offset where the selection started
|
||||
* focus Offset where the caret is
|
||||
*/
|
||||
NotifyIMESelection(PRUint32 anchor, PRUint32 focus);
|
||||
NotifyIMESelection(PRUint32 seqno, PRUint32 anchor, PRUint32 focus);
|
||||
|
||||
/**
|
||||
* Notifies chrome to refresh its text cache
|
||||
|
|
|
@ -115,6 +115,11 @@ parent:
|
|||
GeolocationStart();
|
||||
GeolocationStop();
|
||||
|
||||
ConsoleMessage(nsString message);
|
||||
ScriptError(nsString message, nsString sourceName, nsString sourceLine,
|
||||
PRUint32 lineNumber, PRUint32 colNumber, PRUint32 flags,
|
||||
nsCString category);
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, nsString aJSON);
|
||||
|
||||
|
|
|
@ -317,12 +317,14 @@ TabParent::RecvAsyncMessage(const nsString& aMessage,
|
|||
|
||||
bool
|
||||
TabParent::RecvNotifyIMEFocus(const PRBool& aFocus,
|
||||
nsIMEUpdatePreference* aPreference)
|
||||
nsIMEUpdatePreference* aPreference,
|
||||
PRUint32* aSeqno)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
*aSeqno = mIMESeqno;
|
||||
mIMETabParent = aFocus ? this : nsnull;
|
||||
mIMESelectionAnchor = 0;
|
||||
mIMESelectionFocus = 0;
|
||||
|
@ -355,16 +357,19 @@ TabParent::RecvNotifyIMETextChange(const PRUint32& aStart,
|
|||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvNotifyIMESelection(const PRUint32& aAnchor,
|
||||
TabParent::RecvNotifyIMESelection(const PRUint32& aSeqno,
|
||||
const PRUint32& aAnchor,
|
||||
const PRUint32& aFocus)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return true;
|
||||
|
||||
mIMESelectionAnchor = aAnchor;
|
||||
mIMESelectionFocus = aFocus;
|
||||
widget->OnIMESelectionChange();
|
||||
if (aSeqno == mIMESeqno) {
|
||||
mIMESelectionAnchor = aAnchor;
|
||||
mIMESelectionFocus = aFocus;
|
||||
widget->OnIMESelectionChange();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -444,12 +449,13 @@ TabParent::HandleQueryContentEvent(nsQueryContentEvent& aEvent)
|
|||
}
|
||||
|
||||
bool
|
||||
TabParent::SendCompositionEvent(const nsCompositionEvent& event)
|
||||
TabParent::SendCompositionEvent(nsCompositionEvent& event)
|
||||
{
|
||||
mIMEComposing = event.message == NS_COMPOSITION_START;
|
||||
mIMECompositionStart = PR_MIN(mIMESelectionAnchor, mIMESelectionFocus);
|
||||
if (mIMECompositionEnding)
|
||||
return true;
|
||||
event.seqno = ++mIMESeqno;
|
||||
return PBrowserParent::SendCompositionEvent(event);
|
||||
}
|
||||
|
||||
|
@ -461,7 +467,7 @@ TabParent::SendCompositionEvent(const nsCompositionEvent& event)
|
|||
* here and pass the text as the EndIMEComposition return value
|
||||
*/
|
||||
bool
|
||||
TabParent::SendTextEvent(const nsTextEvent& event)
|
||||
TabParent::SendTextEvent(nsTextEvent& event)
|
||||
{
|
||||
if (mIMECompositionEnding) {
|
||||
mIMECompositionText = event.theText;
|
||||
|
@ -476,14 +482,16 @@ TabParent::SendTextEvent(const nsTextEvent& event)
|
|||
mIMESelectionAnchor = mIMESelectionFocus =
|
||||
mIMECompositionStart + event.theText.Length();
|
||||
|
||||
event.seqno = ++mIMESeqno;
|
||||
return PBrowserParent::SendTextEvent(event);
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::SendSelectionEvent(const nsSelectionEvent& event)
|
||||
TabParent::SendSelectionEvent(nsSelectionEvent& event)
|
||||
{
|
||||
mIMESelectionAnchor = event.mOffset + (event.mReversed ? event.mLength : 0);
|
||||
mIMESelectionFocus = event.mOffset + (!event.mReversed ? event.mLength : 0);
|
||||
event.seqno = ++mIMESeqno;
|
||||
return PBrowserParent::SendSelectionEvent(event);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,11 +92,13 @@ public:
|
|||
virtual bool RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON);
|
||||
virtual bool RecvNotifyIMEFocus(const PRBool& aFocus,
|
||||
nsIMEUpdatePreference* aPreference);
|
||||
nsIMEUpdatePreference* aPreference,
|
||||
PRUint32* aSeqno);
|
||||
virtual bool RecvNotifyIMETextChange(const PRUint32& aStart,
|
||||
const PRUint32& aEnd,
|
||||
const PRUint32& aNewEnd);
|
||||
virtual bool RecvNotifyIMESelection(const PRUint32& aAnchor,
|
||||
virtual bool RecvNotifyIMESelection(const PRUint32& aSeqno,
|
||||
const PRUint32& aAnchor,
|
||||
const PRUint32& aFocus);
|
||||
virtual bool RecvNotifyIMETextHint(const nsString& aText);
|
||||
virtual bool RecvEndIMEComposition(const PRBool& aCancel,
|
||||
|
@ -179,9 +181,9 @@ public:
|
|||
|
||||
static TabParent *GetIMETabParent() { return mIMETabParent; }
|
||||
bool HandleQueryContentEvent(nsQueryContentEvent& aEvent);
|
||||
bool SendCompositionEvent(const nsCompositionEvent& event);
|
||||
bool SendTextEvent(const nsTextEvent& event);
|
||||
bool SendSelectionEvent(const nsSelectionEvent& event);
|
||||
bool SendCompositionEvent(nsCompositionEvent& event);
|
||||
bool SendTextEvent(nsTextEvent& event);
|
||||
bool SendSelectionEvent(nsSelectionEvent& event);
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
PRBool aSync,
|
||||
|
@ -232,6 +234,7 @@ protected:
|
|||
// Compositions in almost all cases are small enough for nsAutoString
|
||||
nsAutoString mIMECompositionText;
|
||||
PRUint32 mIMECompositionStart;
|
||||
PRUint32 mIMESeqno;
|
||||
|
||||
private:
|
||||
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
|
||||
|
|
|
@ -3,25 +3,32 @@
|
|||
<head>
|
||||
<title>postMessage chrome message receiver</title>
|
||||
<script type="application/javascript">
|
||||
var gPrePath = "";
|
||||
|
||||
function receiveMessage(evt)
|
||||
{
|
||||
// Content cannot post to chrome without privileges
|
||||
window.parent.postMessage("SHOULD NOT GET THIS!", "*");
|
||||
if (evt.data.substring(0,9) == "chrome://") {
|
||||
gPrePath = evt.data;
|
||||
respond("path-is-set");
|
||||
} else {
|
||||
// Content cannot post to chrome without privileges
|
||||
window.parent.postMessage("SHOULD NOT GET THIS!", "*");
|
||||
|
||||
var msg = "post-to-content-response";
|
||||
var msg = "post-to-content-response";
|
||||
|
||||
if (evt.source !== null)
|
||||
msg += " wrong-source(" + evt.source + ")";
|
||||
if (!evt.isTrusted)
|
||||
msg += " unexpected-untrusted-event";
|
||||
if (evt.type !== "message")
|
||||
msg += " wrong-type(" + evt.type + ")";
|
||||
if (evt.origin !== "chrome://mochikit")
|
||||
msg += " wrong-origin(" + evt.origin + ")";
|
||||
if (evt.data !== "post-to-content")
|
||||
msg += " wrong-message(" + evt.data + ")";
|
||||
if (evt.source !== null)
|
||||
msg += " wrong-source(" + evt.source + ")";
|
||||
if (!evt.isTrusted)
|
||||
msg += " unexpected-untrusted-event";
|
||||
if (evt.type !== "message")
|
||||
msg += " wrong-type(" + evt.type + ")";
|
||||
if (evt.origin !== gPrePath)
|
||||
msg += " wrong-origin(" + evt.origin + ")";
|
||||
if (evt.data !== "post-to-content")
|
||||
msg += " wrong-message(" + evt.data + ")";
|
||||
|
||||
respond(msg);
|
||||
respond(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function respond(msg)
|
||||
|
|
|
@ -45,6 +45,10 @@ function messageReceiver(evt)
|
|||
|
||||
switch (evt.data)
|
||||
{
|
||||
case "path-is-set":
|
||||
chromePathIsSet(evt);
|
||||
break;
|
||||
|
||||
case "post-to-self":
|
||||
checkSelf(evt);
|
||||
break;
|
||||
|
@ -73,11 +77,16 @@ function checkSelf(evt)
|
|||
is(evt.origin, prepath, "wrong origin for chrome: URL");
|
||||
is(evt.source, null, "chrome posters get a null source, for security");
|
||||
|
||||
window.frames.contentDomain.postMessage(prepath, "*");
|
||||
}
|
||||
|
||||
|
||||
function chromePathIsSet(evt)
|
||||
{
|
||||
window.frames.contentDomain.postMessage("post-to-content",
|
||||
"http://example.org");
|
||||
}
|
||||
|
||||
|
||||
/*************
|
||||
* RECEIVERS *
|
||||
*************/
|
||||
|
|
|
@ -374,40 +374,6 @@ abstract public class GeckoApp
|
|||
unpackFile(zip, buf, entry, entry.getName());
|
||||
}
|
||||
}
|
||||
|
||||
ZipEntry componentsList = zip.getEntry("components/components.manifest");
|
||||
if (componentsList == null) {
|
||||
Log.i("GeckoAppJava", "Can't find components.manifest!");
|
||||
return;
|
||||
}
|
||||
|
||||
listStream = new BufferedInputStream(zip.getInputStream(componentsList));
|
||||
|
||||
StreamTokenizer tkn = new StreamTokenizer(new InputStreamReader(listStream));
|
||||
String line = "components/";
|
||||
int status;
|
||||
boolean addnext = false;
|
||||
tkn.eolIsSignificant(true);
|
||||
do {
|
||||
status = tkn.nextToken();
|
||||
switch (status) {
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if (tkn.sval.equals("binary-component"))
|
||||
addnext = true;
|
||||
else if (addnext) {
|
||||
line += tkn.sval;
|
||||
addnext = false;
|
||||
}
|
||||
break;
|
||||
case StreamTokenizer.TT_NUMBER:
|
||||
break;
|
||||
case StreamTokenizer.TT_EOF:
|
||||
case StreamTokenizer.TT_EOL:
|
||||
unpackFile(zip, buf, null, line);
|
||||
line = "components/";
|
||||
break;
|
||||
}
|
||||
} while (status != StreamTokenizer.TT_EOF);
|
||||
}
|
||||
|
||||
private void unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
|
||||
|
|
|
@ -3791,6 +3791,89 @@ FAIL_CREATEHANDLE:
|
|||
return _cairo_surface_create_in_error(_cairo_error(status));
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_d2d_surface_create_for_texture(cairo_device_t *device,
|
||||
ID3D10Texture2D *texture,
|
||||
cairo_content_t content)
|
||||
{
|
||||
cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
||||
cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
||||
new (newSurf) cairo_d2d_surface_t();
|
||||
|
||||
D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
||||
if (content == CAIRO_CONTENT_COLOR) {
|
||||
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
|
||||
alpha = D2D1_ALPHA_MODE_IGNORE;
|
||||
} else {
|
||||
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
|
||||
}
|
||||
|
||||
D2D1_SIZE_U sizePixels;
|
||||
HRESULT hr;
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
RefPtr<IDXGISurface> dxgiSurface;
|
||||
D2D1_BITMAP_PROPERTIES bitProps;
|
||||
D2D1_RENDER_TARGET_PROPERTIES props;
|
||||
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
sizePixels.width = desc.Width;
|
||||
sizePixels.height = desc.Height;
|
||||
|
||||
newSurf->surface = texture;
|
||||
|
||||
/** Create the DXGI surface. */
|
||||
hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
|
||||
if (FAILED(hr)) {
|
||||
goto FAIL_CREATE;
|
||||
}
|
||||
|
||||
props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||||
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha));
|
||||
|
||||
if (desc.MiscFlags & D3D10_RESOURCE_MISC_GDI_COMPATIBLE)
|
||||
props.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
|
||||
|
||||
hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
||||
props,
|
||||
&newSurf->rt);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto FAIL_CREATE;
|
||||
}
|
||||
|
||||
bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
||||
alpha));
|
||||
|
||||
if (content != CAIRO_CONTENT_ALPHA) {
|
||||
/* For some reason creation of shared bitmaps for A8 UNORM surfaces
|
||||
* doesn't work even though the documentation suggests it does. The
|
||||
* function will return an error if we try */
|
||||
hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
|
||||
dxgiSurface,
|
||||
&bitProps,
|
||||
&newSurf->surfaceBitmap);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto FAIL_CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
||||
|
||||
newSurf->device = d2d_device;
|
||||
cairo_addref_device(device);
|
||||
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
|
||||
|
||||
return reinterpret_cast<cairo_surface_t*>(newSurf);
|
||||
|
||||
FAIL_CREATE:
|
||||
newSurf->~cairo_d2d_surface_t();
|
||||
free(newSurf);
|
||||
return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
|
||||
}
|
||||
|
||||
void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip)
|
||||
{
|
||||
if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
||||
|
|
|
@ -217,6 +217,22 @@ cairo_d2d_surface_create(cairo_device_t *device,
|
|||
cairo_public cairo_surface_t *
|
||||
cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo_content_t content);
|
||||
|
||||
/**
|
||||
* Create a D3D surface from an ID3D10Texture2D texture, this is obtained from a
|
||||
* CreateTexture2D call on a D3D10 device. This has to be an A8R8G8B8 format
|
||||
* or an A8 format, the treatment of the alpha channel can be indicated using
|
||||
* the content parameter.
|
||||
*
|
||||
* \param device Device used to create the surface
|
||||
* \param texture Texture that we want to wrap
|
||||
* \param content Content of the texture
|
||||
* \return New cairo surface
|
||||
*/
|
||||
cairo_public cairo_surface_t *
|
||||
cairo_d2d_surface_create_for_texture(cairo_device_t *device,
|
||||
struct ID3D10Texture2D *texture,
|
||||
cairo_content_t content);
|
||||
|
||||
/**
|
||||
* Present the backbuffer for a surface create for an HWND. This needs
|
||||
* to be called when the owner of the original window surface wants to
|
||||
|
|
|
@ -224,7 +224,8 @@ public:
|
|||
enum LayersBackend {
|
||||
LAYERS_BASIC = 0,
|
||||
LAYERS_OPENGL,
|
||||
LAYERS_D3D9
|
||||
LAYERS_D3D9,
|
||||
LAYERS_D3D10
|
||||
};
|
||||
|
||||
LayerManager() : mDestroyed(PR_FALSE)
|
||||
|
|
|
@ -43,6 +43,7 @@ VPATH = \
|
|||
$(srcdir)/basic \
|
||||
$(srcdir)/opengl \
|
||||
$(srcdir)/d3d9 \
|
||||
$(srcdir)/d3d10 \
|
||||
$(NULL)
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
@ -100,6 +101,20 @@ CPPSRCS += \
|
|||
Nv3DVUtils.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
ifdef MOZ_ENABLE_D3D10_LAYER
|
||||
EXPORTS += \
|
||||
LayerManagerD3D10.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS += \
|
||||
LayerManagerD3D10.cpp \
|
||||
ThebesLayerD3D10.cpp \
|
||||
ContainerLayerD3D10.cpp \
|
||||
ImageLayerD3D10.cpp \
|
||||
ColorLayerD3D10.cpp \
|
||||
CanvasLayerD3D10.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MOZ_IPC #{
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* 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 "CanvasLayerD3D10.h"
|
||||
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxWindowsSurface.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
CanvasLayerD3D10::~CanvasLayerD3D10()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CanvasLayerD3D10::Initialize(const Data& aData)
|
||||
{
|
||||
NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
|
||||
|
||||
if (aData.mSurface) {
|
||||
mSurface = aData.mSurface;
|
||||
NS_ASSERTION(aData.mGLContext == nsnull,
|
||||
"CanvasLayer can't have both surface and GLContext");
|
||||
mNeedsYFlip = PR_FALSE;
|
||||
mDataIsPremultiplied = PR_TRUE;
|
||||
} else if (aData.mGLContext) {
|
||||
NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
|
||||
mGLContext = aData.mGLContext;
|
||||
mCanvasFramebuffer = mGLContext->GetOffscreenFBO();
|
||||
mDataIsPremultiplied = aData.mGLBufferIsPremultiplied;
|
||||
mNeedsYFlip = PR_TRUE;
|
||||
} else {
|
||||
NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
|
||||
}
|
||||
|
||||
mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
|
||||
|
||||
if (mSurface && mSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
|
||||
void *data = mSurface->GetData(&gKeyD3D10Texture);
|
||||
if (data) {
|
||||
mTexture = static_cast<ID3D10Texture2D*>(data);
|
||||
mIsD2DTexture = true;
|
||||
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mIsD2DTexture = false;
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1);
|
||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||
|
||||
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to create texture for CanvasLayer!");
|
||||
return;
|
||||
}
|
||||
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasLayerD3D10::Updated(const nsIntRect& aRect)
|
||||
{
|
||||
if (mIsD2DTexture) {
|
||||
mSurface->Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGLContext) {
|
||||
// WebGL reads entire surface.
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
|
||||
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to map CanvasLayer texture.");
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint8 *destination;
|
||||
if (map.RowPitch != mBounds.width * 4) {
|
||||
destination = new PRUint8[mBounds.width * mBounds.height * 4];
|
||||
} else {
|
||||
destination = (PRUint8*)map.pData;
|
||||
}
|
||||
|
||||
// We have to flush to ensure that any buffered GL operations are
|
||||
// in the framebuffer before we read.
|
||||
mGLContext->fFlush();
|
||||
|
||||
PRUint32 currentFramebuffer = 0;
|
||||
|
||||
mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)¤tFramebuffer);
|
||||
|
||||
// Make sure that we read pixels from the correct framebuffer, regardless
|
||||
// of what's currently bound.
|
||||
if (currentFramebuffer != mCanvasFramebuffer)
|
||||
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
|
||||
|
||||
// For simplicity, we read the entire framebuffer for now -- in
|
||||
// the future we should use aRect, though with WebGL we don't
|
||||
// have an easy way to generate one.
|
||||
nsRefPtr<gfxImageSurface> tmpSurface =
|
||||
new gfxImageSurface(destination,
|
||||
gfxIntSize(mBounds.width, mBounds.height),
|
||||
mBounds.width * 4,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
mGLContext->ReadPixelsIntoImageSurface(0, 0,
|
||||
mBounds.width, mBounds.height,
|
||||
tmpSurface);
|
||||
tmpSurface = nsnull;
|
||||
|
||||
// Put back the previous framebuffer binding.
|
||||
if (currentFramebuffer != mCanvasFramebuffer)
|
||||
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
|
||||
|
||||
if (map.RowPitch != mBounds.width * 4) {
|
||||
for (int y = 0; y < mBounds.height; y++) {
|
||||
memcpy((PRUint8*)map.pData + map.RowPitch * y,
|
||||
destination + mBounds.width * 4 * y,
|
||||
mBounds.width * 4);
|
||||
}
|
||||
delete [] destination;
|
||||
}
|
||||
mTexture->Unmap(0);
|
||||
} else if (mSurface) {
|
||||
RECT r;
|
||||
r.left = aRect.x;
|
||||
r.top = aRect.y;
|
||||
r.right = aRect.XMost();
|
||||
r.bottom = aRect.YMost();
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to lock CanvasLayer texture.");
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint8 *startBits;
|
||||
PRUint32 sourceStride;
|
||||
|
||||
nsRefPtr<gfxImageSurface> dstSurface;
|
||||
|
||||
dstSurface = new gfxImageSurface((unsigned char*)map.pData,
|
||||
gfxIntSize(aRect.width, aRect.height),
|
||||
map.RowPitch,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(dstSurface);
|
||||
ctx->Translate(gfxPoint(-aRect.x, -aRect.y));
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->SetSource(mSurface);
|
||||
ctx->Paint();
|
||||
|
||||
mTexture->Unmap(0);
|
||||
}
|
||||
}
|
||||
|
||||
Layer*
|
||||
CanvasLayerD3D10::GetLayer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
|
||||
{
|
||||
if (!mTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
gfx3DMatrix transform = mTransform * aTransform;
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
|
||||
effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
|
||||
if (mDataIsPremultiplied) {
|
||||
if (mSurface && mSurface->GetContentType() == gfxASurface::CONTENT_COLOR) {
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBLayerPremulPoint");
|
||||
} else {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBLayerPremul");
|
||||
}
|
||||
} else {
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
|
||||
} else {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerNonPremulPoint");
|
||||
} else {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerNonPremul");
|
||||
}
|
||||
}
|
||||
|
||||
if (mSRView) {
|
||||
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView);
|
||||
}
|
||||
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)mBounds.x,
|
||||
(float)mBounds.y,
|
||||
(float)mBounds.width,
|
||||
(float)mBounds.height)
|
||||
);
|
||||
|
||||
if (mNeedsYFlip) {
|
||||
effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
0,
|
||||
1.0f,
|
||||
1.0f,
|
||||
-1.0f)
|
||||
);
|
||||
}
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
device()->Draw(4, 0);
|
||||
|
||||
if (mNeedsYFlip) {
|
||||
effect()->GetVariableByName("vTextureCoords")->AsVector()->
|
||||
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
* 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 GFX_CANVASLAYEROGL_H
|
||||
#define GFX_CANVASLAYEROGL_H
|
||||
|
||||
#include "LayerManagerD3D10.h"
|
||||
#include "GLContext.h"
|
||||
#include "gfxASurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class THEBES_API CanvasLayerD3D10 : public CanvasLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
public:
|
||||
CanvasLayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: CanvasLayer(aManager, NULL),
|
||||
LayerD3D10(aManager),
|
||||
mTexture(0),
|
||||
mDataIsPremultiplied(PR_FALSE),
|
||||
mNeedsYFlip(PR_FALSE)
|
||||
{
|
||||
mImplData = static_cast<LayerD3D10*>(this);
|
||||
}
|
||||
|
||||
~CanvasLayerD3D10();
|
||||
|
||||
// CanvasLayer implementation
|
||||
virtual void Initialize(const Data& aData);
|
||||
virtual void Updated(const nsIntRect& aRect);
|
||||
|
||||
// LayerD3D10 implementation
|
||||
virtual Layer* GetLayer();
|
||||
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
|
||||
private:
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
nsRefPtr<GLContext> mGLContext;
|
||||
|
||||
PRUint32 mCanvasFramebuffer;
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> mTexture;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
|
||||
nsIntRect mBounds;
|
||||
|
||||
PRPackedBool mDataIsPremultiplied;
|
||||
PRPackedBool mNeedsYFlip;
|
||||
PRPackedBool mIsD2DTexture;
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
#endif /* GFX_CANVASLAYERD3D10_H */
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert O'Callahan <robert@ocallahan.org>
|
||||
* 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 "ColorLayerD3D10.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ColorLayerD3D10::ColorLayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: ColorLayer(aManager, NULL)
|
||||
, LayerD3D10(aManager)
|
||||
{
|
||||
mImplData = static_cast<LayerD3D10*>(this);
|
||||
}
|
||||
|
||||
Layer*
|
||||
ColorLayerD3D10::GetLayer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
ColorLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
|
||||
{
|
||||
float color[4];
|
||||
// color is premultiplied, so we need to adjust all channels
|
||||
color[0] = (float)(mColor.r * GetOpacity() * aOpacity);
|
||||
color[1] = (float)(mColor.g * GetOpacity() * aOpacity);
|
||||
color[2] = (float)(mColor.b * GetOpacity() * aOpacity);
|
||||
color[3] = (float)(mColor.a * GetOpacity() * aOpacity);
|
||||
|
||||
gfx3DMatrix transform = mTransform * aTransform;
|
||||
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
|
||||
effect()->GetVariableByName("fLayerColor")->AsVector()->SetFloatVector(color);
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
technique = effect()->GetTechniqueByName("RenderSolidColorLayer");
|
||||
|
||||
nsIntRegionRectIterator iter(mVisibleRegion);
|
||||
|
||||
const nsIntRect *iterRect;
|
||||
while ((iterRect = iter.Next())) {
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)iterRect->x,
|
||||
(float)iterRect->y,
|
||||
(float)iterRect->width,
|
||||
(float)iterRect->height)
|
||||
);
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
device()->Draw(4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 GFX_COLORLAYERD3D10_H
|
||||
#define GFX_COLORLAYERD3D10_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "LayerManagerD3D10.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ColorLayerD3D10 : public ColorLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
public:
|
||||
ColorLayerD3D10(LayerManagerD3D10 *aManager);
|
||||
|
||||
/* LayerD3D10 implementation */
|
||||
Layer* GetLayer();
|
||||
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
#endif /* GFX_THEBESLAYERD3D10_H */
|
|
@ -0,0 +1,337 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 "ContainerLayerD3D10.h"
|
||||
#include "nsAlgorithm.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ContainerLayerD3D10::ContainerLayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: ContainerLayer(aManager, NULL)
|
||||
, LayerD3D10(aManager)
|
||||
{
|
||||
mImplData = static_cast<LayerD3D10*>(this);
|
||||
}
|
||||
|
||||
ContainerLayerD3D10::~ContainerLayerD3D10()
|
||||
{
|
||||
while (mFirstChild) {
|
||||
RemoveChild(mFirstChild);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerD3D10::InsertAfter(Layer* aChild, Layer* aAfter)
|
||||
{
|
||||
aChild->SetParent(this);
|
||||
if (!aAfter) {
|
||||
Layer *oldFirstChild = GetFirstChild();
|
||||
mFirstChild = aChild;
|
||||
aChild->SetNextSibling(oldFirstChild);
|
||||
aChild->SetPrevSibling(nsnull);
|
||||
if (oldFirstChild) {
|
||||
oldFirstChild->SetPrevSibling(aChild);
|
||||
}
|
||||
NS_ADDREF(aChild);
|
||||
return;
|
||||
}
|
||||
for (Layer *child = GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
if (aAfter == child) {
|
||||
Layer *oldNextSibling = child->GetNextSibling();
|
||||
child->SetNextSibling(aChild);
|
||||
aChild->SetNextSibling(oldNextSibling);
|
||||
if (oldNextSibling) {
|
||||
oldNextSibling->SetPrevSibling(aChild);
|
||||
}
|
||||
aChild->SetPrevSibling(child);
|
||||
NS_ADDREF(aChild);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_WARNING("Failed to find aAfter layer!");
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerD3D10::RemoveChild(Layer *aChild)
|
||||
{
|
||||
if (GetFirstChild() == aChild) {
|
||||
mFirstChild = GetFirstChild()->GetNextSibling();
|
||||
if (mFirstChild) {
|
||||
mFirstChild->SetPrevSibling(nsnull);
|
||||
}
|
||||
aChild->SetNextSibling(nsnull);
|
||||
aChild->SetPrevSibling(nsnull);
|
||||
aChild->SetParent(nsnull);
|
||||
NS_RELEASE(aChild);
|
||||
return;
|
||||
}
|
||||
Layer *lastChild = nsnull;
|
||||
for (Layer *child = GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child == aChild) {
|
||||
// We're sure this is not our first child. So lastChild != NULL.
|
||||
lastChild->SetNextSibling(child->GetNextSibling());
|
||||
if (child->GetNextSibling()) {
|
||||
child->GetNextSibling()->SetPrevSibling(lastChild);
|
||||
}
|
||||
child->SetNextSibling(nsnull);
|
||||
child->SetPrevSibling(nsnull);
|
||||
child->SetParent(nsnull);
|
||||
NS_RELEASE(aChild);
|
||||
return;
|
||||
}
|
||||
lastChild = child;
|
||||
}
|
||||
}
|
||||
|
||||
Layer*
|
||||
ContainerLayerD3D10::GetLayer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
LayerD3D10*
|
||||
ContainerLayerD3D10::GetFirstChildD3D10()
|
||||
{
|
||||
if (!mFirstChild) {
|
||||
return nsnull;
|
||||
}
|
||||
return static_cast<LayerD3D10*>(mFirstChild->ImplData());
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
|
||||
{
|
||||
float renderTargetOffset[] = { 0, 0 };
|
||||
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
float opacity = GetOpacity() * aOpacity;
|
||||
gfx3DMatrix transform = mTransform * aTransform;
|
||||
PRBool useIntermediate = ShouldUseIntermediate(aOpacity, transform);
|
||||
|
||||
nsRefPtr<ID3D10RenderTargetView> previousRTView;
|
||||
nsRefPtr<ID3D10Texture2D> renderTexture;
|
||||
nsRefPtr<ID3D10RenderTargetView> rtView;
|
||||
float previousRenderTargetOffset[2];
|
||||
nsIntSize previousViewportSize;
|
||||
|
||||
gfx3DMatrix oldViewMatrix;
|
||||
|
||||
if (useIntermediate) {
|
||||
device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), NULL);
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC));
|
||||
desc.ArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.Width = visibleRect.width;
|
||||
desc.Height = visibleRect.height;
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture));
|
||||
|
||||
device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView));
|
||||
|
||||
float black[] = { 0, 0, 0, 0};
|
||||
device()->ClearRenderTargetView(rtView, black);
|
||||
|
||||
ID3D10RenderTargetView *rtViewPtr = rtView;
|
||||
device()->OMSetRenderTargets(1, &rtViewPtr, NULL);
|
||||
|
||||
effect()->GetVariableByName("vRenderTargetOffset")->
|
||||
GetRawValue(previousRenderTargetOffset, 0, 8);
|
||||
|
||||
renderTargetOffset[0] = (float)visibleRect.x;
|
||||
renderTargetOffset[1] = (float)visibleRect.y;
|
||||
effect()->GetVariableByName("vRenderTargetOffset")->
|
||||
SetRawValue(renderTargetOffset, 0, 8);
|
||||
|
||||
previousViewportSize = mD3DManager->GetViewport();
|
||||
mD3DManager->SetViewport(nsIntSize(visibleRect.Size()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Render this container's contents.
|
||||
*/
|
||||
LayerD3D10 *layerToRender = GetFirstChildD3D10();
|
||||
while (layerToRender) {
|
||||
const nsIntRect *clipRect = layerToRender->GetLayer()->GetClipRect();
|
||||
|
||||
D3D10_RECT oldScissor;
|
||||
if (clipRect || useIntermediate) {
|
||||
UINT numRects = 1;
|
||||
device()->RSGetScissorRects(&numRects, &oldScissor);
|
||||
|
||||
RECT r;
|
||||
if (clipRect) {
|
||||
r.left = (LONG)(clipRect->x - renderTargetOffset[0]);
|
||||
r.top = (LONG)(clipRect->y - renderTargetOffset[1]);
|
||||
r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width);
|
||||
r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height);
|
||||
} else {
|
||||
// useIntermediate == true
|
||||
r.left = 0;
|
||||
r.top = 0;
|
||||
r.right = visibleRect.width;
|
||||
r.bottom = visibleRect.height;
|
||||
}
|
||||
|
||||
D3D10_RECT d3drect;
|
||||
if (!useIntermediate) {
|
||||
// Scissor rect should be an intersection of the old and current scissor.
|
||||
r.left = NS_MAX<PRInt32>(oldScissor.left, r.left);
|
||||
r.right = NS_MIN<PRInt32>(oldScissor.right, r.right);
|
||||
r.top = NS_MAX<PRInt32>(oldScissor.top, r.top);
|
||||
r.bottom = NS_MIN<PRInt32>(oldScissor.bottom, r.bottom);
|
||||
}
|
||||
|
||||
if (r.left >= r.right || r.top >= r.bottom) {
|
||||
// Entire layer's clipped out, don't bother drawing.
|
||||
Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
|
||||
layerToRender = nextSibling ? static_cast<LayerD3D10*>(nextSibling->
|
||||
ImplData())
|
||||
: nsnull;
|
||||
continue;
|
||||
}
|
||||
|
||||
d3drect.left = NS_MAX<PRInt32>(r.left, 0);
|
||||
d3drect.top = NS_MAX<PRInt32>(r.top, 0);
|
||||
d3drect.bottom = r.bottom;
|
||||
d3drect.right = r.right;
|
||||
|
||||
device()->RSSetScissorRects(1, &d3drect);
|
||||
}
|
||||
|
||||
// SetScissorRect
|
||||
if (!useIntermediate) {
|
||||
layerToRender->RenderLayer(opacity, transform);
|
||||
} else {
|
||||
layerToRender->RenderLayer(1.0f, gfx3DMatrix());
|
||||
}
|
||||
|
||||
if (clipRect || useIntermediate) {
|
||||
device()->RSSetScissorRects(1, &oldScissor);
|
||||
}
|
||||
|
||||
Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
|
||||
layerToRender = nextSibling ? static_cast<LayerD3D10*>(nextSibling->
|
||||
ImplData())
|
||||
: nsnull;
|
||||
}
|
||||
|
||||
if (useIntermediate) {
|
||||
mD3DManager->SetViewport(previousViewportSize);
|
||||
ID3D10RenderTargetView *rtView = previousRTView;
|
||||
device()->OMSetRenderTargets(1, &rtView, NULL);
|
||||
effect()->GetVariableByName("vRenderTargetOffset")->
|
||||
SetRawValue(previousRenderTargetOffset, 0, 8);
|
||||
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
|
||||
effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(opacity);
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
|
||||
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)visibleRect.x,
|
||||
(float)visibleRect.y,
|
||||
(float)visibleRect.width,
|
||||
(float)visibleRect.height)
|
||||
);
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
|
||||
ID3D10ShaderResourceView *view;
|
||||
device()->CreateShaderResourceView(renderTexture, NULL, &view);
|
||||
device()->PSSetShaderResources(0, 1, &view);
|
||||
device()->Draw(4, 0);
|
||||
view->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerD3D10::LayerManagerDestroyed()
|
||||
{
|
||||
while (mFirstChild) {
|
||||
GetFirstChildD3D10()->LayerManagerDestroyed();
|
||||
RemoveChild(mFirstChild);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerD3D10::Validate()
|
||||
{
|
||||
Layer *layer = GetFirstChild();
|
||||
while (layer) {
|
||||
static_cast<LayerD3D10*>(layer->ImplData())->Validate();
|
||||
layer = layer->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContainerLayerD3D10::ShouldUseIntermediate(float aOpacity,
|
||||
const gfx3DMatrix &aMatrix)
|
||||
{
|
||||
if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Layer *firstChild = GetFirstChild();
|
||||
|
||||
if (!firstChild || (!firstChild->GetNextSibling() &&
|
||||
!firstChild->GetClipRect())) {
|
||||
// If we forward our transform to a child without using an intermediate, we
|
||||
// need to be sure that child does not have a clip rect since the clip rect
|
||||
// needs to be applied after its transform.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aMatrix.IsIdentity() && (!firstChild || !firstChild->GetNextSibling())) {
|
||||
// If there's no transforms applied and a single child, opacity can always
|
||||
// be forwarded to our only child.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 GFX_CONTAINERLAYERD3D10_H
|
||||
#define GFX_CONTAINERLAYERD3D10_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "LayerManagerD3D10.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ContainerLayerD3D10 : public ContainerLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
public:
|
||||
ContainerLayerD3D10(LayerManagerD3D10 *aManager);
|
||||
~ContainerLayerD3D10();
|
||||
|
||||
nsIntRect GetVisibleRect() { return mVisibleRegion.GetBounds(); }
|
||||
|
||||
/* ContainerLayer implementation */
|
||||
virtual void InsertAfter(Layer* aChild, Layer* aAfter);
|
||||
|
||||
virtual void RemoveChild(Layer* aChild);
|
||||
|
||||
/* LayerD3D10 implementation */
|
||||
Layer* GetLayer();
|
||||
|
||||
LayerD3D10* GetFirstChildD3D10();
|
||||
|
||||
void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
void Validate();
|
||||
|
||||
virtual void LayerManagerDestroyed();
|
||||
|
||||
private:
|
||||
bool ShouldUseIntermediate(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
|
||||
#endif /* GFX_CONTAINERLAYERD3D10_H */
|
|
@ -0,0 +1,395 @@
|
|||
/* -*- Mode: C++; tab-width: 20; 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) 2009
|
||||
* 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 "ImageLayerD3D10.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "yuv_convert.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using mozilla::MutexAutoLock;
|
||||
|
||||
ImageContainerD3D10::ImageContainerD3D10(LayerManagerD3D10 *aManager)
|
||||
: ImageContainer(aManager)
|
||||
, mActiveImageLock("mozilla.layers.ImageContainerD3D10.mActiveImageLock")
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D10::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
img = new PlanarYCbCrImageD3D10(static_cast<LayerManagerD3D10*>(mManager));
|
||||
} else if (aFormats[0] == Image::CAIRO_SURFACE) {
|
||||
img = new CairoImageD3D10(static_cast<LayerManagerD3D10*>(mManager));
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainerD3D10::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
MutexAutoLock lock(mActiveImageLock);
|
||||
|
||||
mActiveImage = aImage;
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D10::GetCurrentImage()
|
||||
{
|
||||
MutexAutoLock lock(mActiveImageLock);
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainerD3D10::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
MutexAutoLock lock(mActiveImageLock);
|
||||
if (!mActiveImage) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(mActiveImage.get());
|
||||
if (yuvImage->HasData()) {
|
||||
*aSize = yuvImage->mSize;
|
||||
}
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(mActiveImage.get());
|
||||
*aSize = cairoImage->mSize;
|
||||
}
|
||||
|
||||
return static_cast<ImageD3D10*>(mActiveImage->GetImplData())->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainerD3D10::GetCurrentSize()
|
||||
{
|
||||
MutexAutoLock lock(mActiveImageLock);
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(mActiveImage.get());
|
||||
if (!yuvImage->HasData()) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
return yuvImage->mSize;
|
||||
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(mActiveImage.get());
|
||||
return cairoImage->mSize;
|
||||
}
|
||||
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
PRBool
|
||||
ImageContainerD3D10::SetLayerManager(LayerManager *aManager)
|
||||
{
|
||||
// we can't do anything here for now
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
Layer*
|
||||
ImageLayerD3D10::GetLayer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
|
||||
{
|
||||
if (!GetContainer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
|
||||
|
||||
|
||||
gfx3DMatrix transform = mTransform * aTransform;
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
|
||||
effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
|
||||
if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(image.get());
|
||||
|
||||
if (!yuvImage->HasData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: At some point we should try to deal with mFilter here, you don't
|
||||
// really want to use point filtering in the case of NEAREST, since that
|
||||
// would also use point filtering for Chroma upsampling. Where most likely
|
||||
// the user would only want point filtering for final RGB image upsampling.
|
||||
|
||||
technique = effect()->GetTechniqueByName("RenderYCbCrLayer");
|
||||
|
||||
effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(yuvImage->mYView);
|
||||
effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(yuvImage->mCbView);
|
||||
effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(yuvImage->mCrView);
|
||||
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)0,
|
||||
(float)0,
|
||||
(float)yuvImage->mSize.width,
|
||||
(float)yuvImage->mSize.height)
|
||||
);
|
||||
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(image.get());
|
||||
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
|
||||
} else {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
|
||||
}
|
||||
|
||||
if (cairoImage->mSRView) {
|
||||
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(cairoImage->mSRView);
|
||||
}
|
||||
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)0,
|
||||
(float)0,
|
||||
(float)cairoImage->mSize.width,
|
||||
(float)cairoImage->mSize.height)
|
||||
);
|
||||
}
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
device()->Draw(4, 0);
|
||||
}
|
||||
|
||||
PlanarYCbCrImageD3D10::PlanarYCbCrImageD3D10(mozilla::layers::LayerManagerD3D10* aManager)
|
||||
: PlanarYCbCrImage(static_cast<ImageD3D10*>(this))
|
||||
, mManager(aManager)
|
||||
, mHasData(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D10::SetData(const PlanarYCbCrImage::Data &aData)
|
||||
{
|
||||
// XXX - For D3D10Ex we really should just copy to systemmem surfaces here.
|
||||
// For now, we copy the data
|
||||
int width_shift = 0;
|
||||
int height_shift = 0;
|
||||
if (aData.mYSize.width == aData.mCbCrSize.width &&
|
||||
aData.mYSize.height == aData.mCbCrSize.height) {
|
||||
// YV24 format
|
||||
width_shift = 0;
|
||||
height_shift = 0;
|
||||
mType = gfx::YV24;
|
||||
} else if (aData.mYSize.width / 2 == aData.mCbCrSize.width &&
|
||||
aData.mYSize.height == aData.mCbCrSize.height) {
|
||||
// YV16 format
|
||||
width_shift = 1;
|
||||
height_shift = 0;
|
||||
mType = gfx::YV16;
|
||||
} else if (aData.mYSize.width / 2 == aData.mCbCrSize.width &&
|
||||
aData.mYSize.height / 2 == aData.mCbCrSize.height ) {
|
||||
// YV12 format
|
||||
width_shift = 1;
|
||||
height_shift = 1;
|
||||
mType = gfx::YV12;
|
||||
} else {
|
||||
NS_ERROR("YCbCr format not supported");
|
||||
}
|
||||
|
||||
mData = aData;
|
||||
mData.mCbCrStride = mData.mCbCrSize.width = aData.mPicSize.width >> width_shift;
|
||||
// Round up the values for width and height to make sure we sample enough data
|
||||
// for the last pixel - See bug 590735
|
||||
if (width_shift && (aData.mPicSize.width & 1)) {
|
||||
mData.mCbCrStride++;
|
||||
mData.mCbCrSize.width++;
|
||||
}
|
||||
mData.mCbCrSize.height = aData.mPicSize.height >> height_shift;
|
||||
if (height_shift && (aData.mPicSize.height & 1)) {
|
||||
mData.mCbCrSize.height++;
|
||||
}
|
||||
mData.mYSize = aData.mPicSize;
|
||||
mData.mYStride = mData.mYSize.width;
|
||||
|
||||
mBuffer = new PRUint8[mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height];
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
int cbcr_x = aData.mPicX >> width_shift;
|
||||
int cbcr_y = aData.mPicY >> height_shift;
|
||||
|
||||
for (int i = 0; i < mData.mYSize.height; i++) {
|
||||
memcpy(mData.mYChannel + i * mData.mYStride,
|
||||
aData.mYChannel + ((aData.mPicY + i) * aData.mYStride) + aData.mPicX,
|
||||
mData.mYStride);
|
||||
}
|
||||
for (int i = 0; i < mData.mCbCrSize.height; i++) {
|
||||
memcpy(mData.mCbChannel + i * mData.mCbCrStride,
|
||||
aData.mCbChannel + ((cbcr_y + i) * aData.mCbCrStride) + cbcr_x,
|
||||
mData.mCbCrStride);
|
||||
}
|
||||
for (int i = 0; i < mData.mCbCrSize.height; i++) {
|
||||
memcpy(mData.mCrChannel + i * mData.mCbCrStride,
|
||||
aData.mCrChannel + ((cbcr_y + i) * aData.mCbCrStride) + cbcr_x,
|
||||
mData.mCbCrStride);
|
||||
}
|
||||
|
||||
// Fix picture rect to be correct
|
||||
mData.mPicX = mData.mPicY = 0;
|
||||
mSize = aData.mPicSize;
|
||||
|
||||
AllocateTextures();
|
||||
|
||||
mHasData = PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D10::AllocateTextures()
|
||||
{
|
||||
D3D10_SUBRESOURCE_DATA dataY;
|
||||
D3D10_SUBRESOURCE_DATA dataCb;
|
||||
D3D10_SUBRESOURCE_DATA dataCr;
|
||||
CD3D10_TEXTURE2D_DESC descY(DXGI_FORMAT_R8_UNORM,
|
||||
mData.mYSize.width,
|
||||
mData.mYSize.height, 1, 1);
|
||||
CD3D10_TEXTURE2D_DESC descCbCr(DXGI_FORMAT_R8_UNORM,
|
||||
mData.mCbCrSize.width,
|
||||
mData.mCbCrSize.height, 1, 1);
|
||||
|
||||
descY.Usage = descCbCr.Usage = D3D10_USAGE_IMMUTABLE;
|
||||
|
||||
dataY.pSysMem = mData.mYChannel;
|
||||
dataY.SysMemPitch = mData.mYStride;
|
||||
dataCb.pSysMem = mData.mCbChannel;
|
||||
dataCb.SysMemPitch = mData.mCbCrStride;
|
||||
dataCr.pSysMem = mData.mCrChannel;
|
||||
dataCr.SysMemPitch = mData.mCbCrStride;
|
||||
|
||||
mManager->device()->CreateTexture2D(&descY, &dataY, getter_AddRefs(mYTexture));
|
||||
mManager->device()->CreateTexture2D(&descCbCr, &dataCb, getter_AddRefs(mCbTexture));
|
||||
mManager->device()->CreateTexture2D(&descCbCr, &dataCr, getter_AddRefs(mCrTexture));
|
||||
mManager->device()->CreateShaderResourceView(mYTexture, NULL, getter_AddRefs(mYView));
|
||||
mManager->device()->CreateShaderResourceView(mCbTexture, NULL, getter_AddRefs(mCbView));
|
||||
mManager->device()->CreateShaderResourceView(mCrTexture, NULL, getter_AddRefs(mCrView));
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImageD3D10::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, gfxASurface::ImageFormatRGB24);
|
||||
|
||||
// Convert from YCbCr to RGB now
|
||||
gfx::ConvertYCbCrToRGB32(mData.mYChannel,
|
||||
mData.mCbChannel,
|
||||
mData.mCrChannel,
|
||||
imageSurface->Data(),
|
||||
0,
|
||||
0,
|
||||
mSize.width,
|
||||
mSize.height,
|
||||
mData.mYStride,
|
||||
mData.mCbCrStride,
|
||||
imageSurface->Stride(),
|
||||
mType);
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
CairoImageD3D10::~CairoImageD3D10()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CairoImageD3D10::SetData(const CairoImage::Data &aData)
|
||||
{
|
||||
mSize = aData.mSize;
|
||||
|
||||
nsRefPtr<gfxImageSurface> imageSurface;
|
||||
|
||||
if (aData.mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
|
||||
imageSurface = static_cast<gfxImageSurface*>(aData.mSurface);
|
||||
} else {
|
||||
imageSurface = new gfxImageSurface(aData.mSize,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
||||
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
|
||||
context->SetSource(aData.mSurface);
|
||||
context->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
context->Paint();
|
||||
}
|
||||
|
||||
D3D10_SUBRESOURCE_DATA data;
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mSize.width, mSize.height, 1, 1);
|
||||
desc.Usage = D3D10_USAGE_IMMUTABLE;
|
||||
|
||||
data.pSysMem = imageSurface->Data();
|
||||
data.SysMemPitch = imageSurface->Stride();
|
||||
|
||||
mManager->device()->CreateTexture2D(&desc, &data, getter_AddRefs(mTexture));
|
||||
mManager->device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
CairoImageD3D10::GetAsSurface()
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
|
@ -0,0 +1,155 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bas Schouten <bschouten@mozilla.org>
|
||||
*
|
||||
* 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 GFX_IMAGELAYERD3D10_H
|
||||
#define GFX_IMAGELAYERD3D10_H
|
||||
|
||||
#include "LayerManagerD3D10.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class THEBES_API ImageContainerD3D10 : public ImageContainer
|
||||
{
|
||||
public:
|
||||
ImageContainerD3D10(LayerManagerD3D10 *aManager);
|
||||
virtual ~ImageContainerD3D10() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
|
||||
virtual void SetCurrentImage(Image* aImage);
|
||||
|
||||
virtual already_AddRefed<Image> GetCurrentImage();
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSize);
|
||||
|
||||
virtual gfxIntSize GetCurrentSize();
|
||||
|
||||
virtual PRBool SetLayerManager(LayerManager *aManager);
|
||||
|
||||
private:
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
|
||||
Mutex mActiveImageLock;
|
||||
};
|
||||
|
||||
class THEBES_API ImageLayerD3D10 : public ImageLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
public:
|
||||
ImageLayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: ImageLayer(aManager, NULL)
|
||||
, LayerD3D10(aManager)
|
||||
{
|
||||
mImplData = static_cast<LayerD3D10*>(this);
|
||||
}
|
||||
|
||||
// LayerD3D10 Implementation
|
||||
virtual Layer* GetLayer();
|
||||
|
||||
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
};
|
||||
|
||||
class THEBES_API ImageD3D10
|
||||
{
|
||||
public:
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
};
|
||||
|
||||
class THEBES_API PlanarYCbCrImageD3D10 : public PlanarYCbCrImage,
|
||||
public ImageD3D10
|
||||
{
|
||||
public:
|
||||
PlanarYCbCrImageD3D10(LayerManagerD3D10 *aManager);
|
||||
~PlanarYCbCrImageD3D10() {}
|
||||
|
||||
virtual void SetData(const Data &aData);
|
||||
|
||||
/*
|
||||
* Upload the data from out mData into our textures. For now we use this to
|
||||
* make sure the textures are created and filled on the main thread.
|
||||
*/
|
||||
void AllocateTextures();
|
||||
|
||||
PRBool HasData() { return mHasData; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
LayerManagerD3D10 *mManager;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
nsRefPtr<ID3D10Texture2D> mYTexture;
|
||||
nsRefPtr<ID3D10Texture2D> mCrTexture;
|
||||
nsRefPtr<ID3D10Texture2D> mCbTexture;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mYView;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mCbView;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mCrView;
|
||||
PRPackedBool mHasData;
|
||||
gfx::YUVType mType;
|
||||
};
|
||||
|
||||
|
||||
class THEBES_API CairoImageD3D10 : public CairoImage,
|
||||
public ImageD3D10
|
||||
{
|
||||
public:
|
||||
CairoImageD3D10(LayerManagerD3D10 *aManager)
|
||||
: CairoImage(static_cast<ImageD3D10*>(this))
|
||||
, mManager(aManager)
|
||||
{ }
|
||||
~CairoImageD3D10();
|
||||
|
||||
virtual void SetData(const Data &aData);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> mTexture;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
gfxIntSize mSize;
|
||||
LayerManagerD3D10 *mManager;
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
#endif /* GFX_IMAGELAYERD3D10_H */
|
|
@ -0,0 +1,502 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 "LayerManagerD3D10.h"
|
||||
#include "LayerManagerD3D10Effect.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfxD2DSurface.h"
|
||||
#include "cairo-win32.h"
|
||||
#include "dxgi.h"
|
||||
|
||||
#include "ContainerLayerD3D10.h"
|
||||
#include "ThebesLayerD3D10.h"
|
||||
#include "ColorLayerD3D10.h"
|
||||
#include "CanvasLayerD3D10.h"
|
||||
#include "ImageLayerD3D10.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
|
||||
void *pData,
|
||||
SIZE_T DataLength,
|
||||
UINT FXFlags,
|
||||
ID3D10Device *pDevice,
|
||||
ID3D10EffectPool *pEffectPool,
|
||||
ID3D10Effect **ppEffect
|
||||
);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float position[2];
|
||||
};
|
||||
|
||||
// {17F88CCB-1F49-4c08-8002-ADA7BD44856D}
|
||||
static const GUID sEffect =
|
||||
{ 0x17f88ccb, 0x1f49, 0x4c08, { 0x80, 0x2, 0xad, 0xa7, 0xbd, 0x44, 0x85, 0x6d } };
|
||||
// {19599D91-912C-4C2F-A8C5-299DE85FBD34}
|
||||
static const GUID sInputLayout =
|
||||
{ 0x19599d91, 0x912c, 0x4c2f, { 0xa8, 0xc5, 0x29, 0x9d, 0xe8, 0x5f, 0xbd, 0x34 } };
|
||||
// {293157D2-09C7-4680-AE27-C28E370E418B}
|
||||
static const GUID sVertexBuffer =
|
||||
{ 0x293157d2, 0x9c7, 0x4680, { 0xae, 0x27, 0xc2, 0x8e, 0x37, 0xe, 0x41, 0x8b } };
|
||||
|
||||
cairo_user_data_key_t gKeyD3D10Texture;
|
||||
|
||||
LayerManagerD3D10::LayerManagerD3D10(nsIWidget *aWidget)
|
||||
: mWidget(aWidget)
|
||||
{
|
||||
}
|
||||
|
||||
LayerManagerD3D10::~LayerManagerD3D10()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LayerManagerD3D10::Initialize()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
cairo_device_t *device = gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
|
||||
if (!device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDevice = cairo_d2d_device_get_device(device);
|
||||
|
||||
UINT size = 4;
|
||||
if (FAILED(mDevice->GetPrivateData(sEffect, &size, mEffect.StartAssignment()))) {
|
||||
D3D10CreateEffectFromMemoryFunc createEffect = (D3D10CreateEffectFromMemoryFunc)
|
||||
GetProcAddress(LoadLibraryA("d3d10_1.dll"), "D3D10CreateEffectFromMemory");
|
||||
|
||||
if (!createEffect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = createEffect((void*)g_main,
|
||||
sizeof(g_main),
|
||||
D3D10_EFFECT_SINGLE_THREADED,
|
||||
mDevice,
|
||||
NULL,
|
||||
getter_AddRefs(mEffect));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDevice->SetPrivateDataInterface(sEffect, mEffect);
|
||||
}
|
||||
|
||||
size = 4;
|
||||
if (FAILED(mDevice->GetPrivateData(sInputLayout, &size, mInputLayout.StartAssignment()))) {
|
||||
D3D10_INPUT_ELEMENT_DESC layout[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
D3D10_PASS_DESC passDesc;
|
||||
mEffect->GetTechniqueByName("RenderRGBLayerPremul")->GetPassByIndex(0)->
|
||||
GetDesc(&passDesc);
|
||||
|
||||
hr = mDevice->CreateInputLayout(layout,
|
||||
sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC),
|
||||
passDesc.pIAInputSignature,
|
||||
passDesc.IAInputSignatureSize,
|
||||
getter_AddRefs(mInputLayout));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDevice->SetPrivateDataInterface(sInputLayout, mInputLayout);
|
||||
}
|
||||
|
||||
size = 4;
|
||||
if (FAILED(mDevice->GetPrivateData(sVertexBuffer, &size, mVertexBuffer.StartAssignment()))) {
|
||||
Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
|
||||
CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
|
||||
D3D10_SUBRESOURCE_DATA data;
|
||||
data.pSysMem = (void*)vertices;
|
||||
|
||||
hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mVertexBuffer));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDevice->SetPrivateDataInterface(sVertexBuffer, mVertexBuffer);
|
||||
}
|
||||
|
||||
nsRefPtr<IDXGIDevice> dxgiDevice;
|
||||
nsRefPtr<IDXGIAdapter> dxgiAdapter;
|
||||
nsRefPtr<IDXGIFactory> dxgiFactory;
|
||||
|
||||
mDevice->QueryInterface(dxgiDevice.StartAssignment());
|
||||
dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
|
||||
|
||||
dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
::ZeroMemory(&swapDesc, sizeof(swapDesc));
|
||||
|
||||
swapDesc.BufferDesc.Width = 0;
|
||||
swapDesc.BufferDesc.Height = 0;
|
||||
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
|
||||
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
|
||||
swapDesc.SampleDesc.Count = 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.BufferCount = 1;
|
||||
swapDesc.OutputWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
swapDesc.Windowed = TRUE;
|
||||
|
||||
/**
|
||||
* Create a swap chain, this swap chain will contain the backbuffer for
|
||||
* the window we draw to. The front buffer is the full screen front
|
||||
* buffer.
|
||||
*/
|
||||
hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::SetRoot(Layer *aRoot)
|
||||
{
|
||||
mRoot = aRoot;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::BeginTransaction()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
mCurrentCallbackInfo.Callback = aCallback;
|
||||
mCurrentCallbackInfo.CallbackData = aCallbackData;
|
||||
Render();
|
||||
mCurrentCallbackInfo.Callback = nsnull;
|
||||
mCurrentCallbackInfo.CallbackData = nsnull;
|
||||
mTarget = nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<ThebesLayer>
|
||||
LayerManagerD3D10::CreateThebesLayer()
|
||||
{
|
||||
nsRefPtr<ThebesLayer> layer = new ThebesLayerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
LayerManagerD3D10::CreateContainerLayer()
|
||||
{
|
||||
nsRefPtr<ContainerLayer> layer = new ContainerLayerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageLayer>
|
||||
LayerManagerD3D10::CreateImageLayer()
|
||||
{
|
||||
nsRefPtr<ImageLayer> layer = new ImageLayerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ColorLayer>
|
||||
LayerManagerD3D10::CreateColorLayer()
|
||||
{
|
||||
nsRefPtr<ColorLayer> layer = new ColorLayerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
LayerManagerD3D10::CreateCanvasLayer()
|
||||
{
|
||||
nsRefPtr<CanvasLayer> layer = new CanvasLayerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
LayerManagerD3D10::CreateImageContainer()
|
||||
{
|
||||
nsRefPtr<ImageContainer> layer = new ImageContainerD3D10(this);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
static void ReleaseTexture(void *texture)
|
||||
{
|
||||
static_cast<ID3D10Texture2D*>(texture)->Release();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
LayerManagerD3D10::CreateOptimalSurface(const gfxIntSize &aSize,
|
||||
gfxASurface::gfxImageFormat aFormat)
|
||||
{
|
||||
if ((aFormat != gfxASurface::ImageFormatRGB24 &&
|
||||
aFormat != gfxASurface::ImageFormatARGB32)) {
|
||||
return LayerManager::CreateOptimalSurface(aSize, aFormat);
|
||||
}
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> texture;
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
|
||||
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(texture));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to create new texture for CreateOptimalSurface!");
|
||||
return LayerManager::CreateOptimalSurface(aSize, aFormat);
|
||||
}
|
||||
|
||||
nsRefPtr<gfxD2DSurface> surface =
|
||||
new gfxD2DSurface(texture, aFormat == gfxASurface::ImageFormatRGB24 ?
|
||||
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
if (!surface || surface->CairoStatus()) {
|
||||
return LayerManager::CreateOptimalSurface(aSize, aFormat);
|
||||
}
|
||||
|
||||
surface->SetData(&gKeyD3D10Texture,
|
||||
texture.forget().get(),
|
||||
ReleaseTexture);
|
||||
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::SetViewport(const nsIntSize &aViewport)
|
||||
{
|
||||
mViewport = aViewport;
|
||||
|
||||
D3D10_VIEWPORT viewport;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
viewport.MinDepth = 0;
|
||||
viewport.Width = aViewport.width;
|
||||
viewport.Height = aViewport.height;
|
||||
viewport.TopLeftX = 0;
|
||||
viewport.TopLeftY = 0;
|
||||
|
||||
mDevice->RSSetViewports(1, &viewport);
|
||||
|
||||
gfx3DMatrix projection;
|
||||
/*
|
||||
* Matrix to transform to viewport space ( <-1.0, 1.0> topleft,
|
||||
* <1.0, -1.0> bottomright)
|
||||
*/
|
||||
projection._11 = 2.0f / aViewport.width;
|
||||
projection._22 = -2.0f / aViewport.height;
|
||||
projection._33 = 1.0f;
|
||||
projection._41 = -1.0f;
|
||||
projection._42 = 1.0f;
|
||||
projection._44 = 1.0f;
|
||||
|
||||
HRESULT hr = mEffect->GetVariableByName("mProjection")->
|
||||
SetRawValue(&projection._11, 0, 64);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to set projection matrix.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::SetupPipeline()
|
||||
{
|
||||
VerifyBufferSize();
|
||||
UpdateRenderTarget();
|
||||
|
||||
nsIntRect rect;
|
||||
mWidget->GetClientBounds(rect);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
hr = mEffect->GetVariableByName("vTextureCoords")->AsVector()->
|
||||
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to set Texture Coordinates.");
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D10RenderTargetView *view = mRTView;
|
||||
mDevice->OMSetRenderTargets(1, &view, NULL);
|
||||
mDevice->IASetInputLayout(mInputLayout);
|
||||
|
||||
UINT stride = sizeof(Vertex);
|
||||
UINT offset = 0;
|
||||
ID3D10Buffer *buffer = mVertexBuffer;
|
||||
mDevice->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);
|
||||
mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
SetViewport(nsIntSize(rect.width, rect.height));
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::UpdateRenderTarget()
|
||||
{
|
||||
if (mRTView) {
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> backBuf;
|
||||
|
||||
hr = mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDevice->CreateRenderTargetView(backBuf, NULL, getter_AddRefs(mRTView));
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::VerifyBufferSize()
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
mSwapChain->GetDesc(&swapDesc);
|
||||
|
||||
nsIntRect rect;
|
||||
mWidget->GetClientBounds(rect);
|
||||
|
||||
if (swapDesc.BufferDesc.Width == rect.width &&
|
||||
swapDesc.BufferDesc.Height == rect.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRTView = nsnull;
|
||||
mSwapChain->ResizeBuffers(1, rect.width, rect.height,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM, 0);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::Render()
|
||||
{
|
||||
if (mRoot) {
|
||||
static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
|
||||
}
|
||||
|
||||
SetupPipeline();
|
||||
|
||||
float black[] = { 0, 0, 0, 0 };
|
||||
device()->ClearRenderTargetView(mRTView, black);
|
||||
|
||||
nsIntRect rect;
|
||||
mWidget->GetClientBounds(rect);
|
||||
|
||||
if (mRoot) {
|
||||
const nsIntRect *clipRect = mRoot->GetClipRect();
|
||||
D3D10_RECT r;
|
||||
if (clipRect) {
|
||||
r.left = (LONG)clipRect->x;
|
||||
r.top = (LONG)clipRect->y;
|
||||
r.right = (LONG)(clipRect->x + clipRect->width);
|
||||
r.bottom = (LONG)(clipRect->y + clipRect->height);
|
||||
} else {
|
||||
r.left = r.top = 0;
|
||||
r.right = rect.width;
|
||||
r.bottom = rect.height;
|
||||
}
|
||||
device()->RSSetScissorRects(1, &r);
|
||||
|
||||
static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer(1, gfx3DMatrix());
|
||||
}
|
||||
|
||||
if (mTarget) {
|
||||
PaintToTarget();
|
||||
} else {
|
||||
mSwapChain->Present(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerD3D10::PaintToTarget()
|
||||
{
|
||||
nsRefPtr<ID3D10Texture2D> backBuf;
|
||||
|
||||
mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
|
||||
|
||||
D3D10_TEXTURE2D_DESC bbDesc;
|
||||
backBuf->GetDesc(&bbDesc);
|
||||
|
||||
CD3D10_TEXTURE2D_DESC softDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height);
|
||||
softDesc.MipLevels = 1;
|
||||
softDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
|
||||
softDesc.Usage = D3D10_USAGE_STAGING;
|
||||
softDesc.BindFlags = 0;
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> readTexture;
|
||||
|
||||
device()->CreateTexture2D(&softDesc, NULL, getter_AddRefs(readTexture));
|
||||
|
||||
device()->CopyResource(readTexture, backBuf);
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
readTexture->Map(0, D3D10_MAP_READ, 0, &map);
|
||||
|
||||
nsRefPtr<gfxImageSurface> tmpSurface =
|
||||
new gfxImageSurface((unsigned char*)map.pData,
|
||||
gfxIntSize(bbDesc.Width, bbDesc.Height),
|
||||
map.RowPitch,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
||||
mTarget->SetSource(tmpSurface);
|
||||
mTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
mTarget->Paint();
|
||||
}
|
||||
|
||||
LayerD3D10::LayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: mD3DManager(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
typedef float4 rect;
|
||||
cbuffer PerLayer {
|
||||
rect vTextureCoords;
|
||||
rect vLayerQuad;
|
||||
float fLayerOpacity;
|
||||
float4x4 mLayerTransform;
|
||||
}
|
||||
|
||||
cbuffer PerOccasionalLayer {
|
||||
float4 vRenderTargetOffset;
|
||||
float4 fLayerColor;
|
||||
}
|
||||
|
||||
cbuffer PerLayerManager {
|
||||
float4x4 mProjection;
|
||||
}
|
||||
|
||||
BlendState Premul
|
||||
{
|
||||
AlphaToCoverageEnable = FALSE;
|
||||
BlendEnable[0] = TRUE;
|
||||
SrcBlend = One;
|
||||
DestBlend = Inv_Src_Alpha;
|
||||
BlendOp = Add;
|
||||
SrcBlendAlpha = One;
|
||||
DestBlendAlpha = Inv_Src_Alpha;
|
||||
BlendOpAlpha = Add;
|
||||
RenderTargetWriteMask[0] = 0x0F; // All
|
||||
};
|
||||
|
||||
BlendState NonPremul
|
||||
{
|
||||
AlphaToCoverageEnable = FALSE;
|
||||
BlendEnable[0] = TRUE;
|
||||
SrcBlend = Src_Alpha;
|
||||
DestBlend = Inv_Src_Alpha;
|
||||
BlendOp = Add;
|
||||
SrcBlendAlpha = One;
|
||||
DestBlendAlpha = Inv_Src_Alpha;
|
||||
BlendOpAlpha = Add;
|
||||
RenderTargetWriteMask[0] = 0x0F; // All
|
||||
};
|
||||
|
||||
RasterizerState LayerRast
|
||||
{
|
||||
ScissorEnable = True;
|
||||
};
|
||||
|
||||
Texture2D tRGB;
|
||||
Texture2D tY;
|
||||
Texture2D tCb;
|
||||
Texture2D tCr;
|
||||
|
||||
SamplerState LayerTextureSamplerLinear
|
||||
{
|
||||
Filter = MIN_MAG_MIP_LINEAR;
|
||||
AddressU = Wrap;
|
||||
AddressV = Wrap;
|
||||
};
|
||||
|
||||
SamplerState LayerTextureSamplerPoint
|
||||
{
|
||||
Filter = MIN_MAG_MIP_POINT;
|
||||
AddressU = Wrap;
|
||||
AddressV = Wrap;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float2 vPosition : POSITION;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT {
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
VS_OUTPUT LayerQuadVS(const VS_INPUT aVertex)
|
||||
{
|
||||
VS_OUTPUT outp;
|
||||
outp.vPosition.z = 0;
|
||||
outp.vPosition.w = 1;
|
||||
|
||||
// We use 4 component floats to uniquely describe a rectangle, by the structure
|
||||
// of x, y, width, height. This allows us to easily generate the 4 corners
|
||||
// of any rectangle from the 4 corners of the 0,0-1,1 quad that we use as the
|
||||
// stream source for our LayerQuad vertex shader. We do this by doing:
|
||||
// Xout = x + Xin * width
|
||||
// Yout = y + Yin * height
|
||||
float2 position = vLayerQuad.xy;
|
||||
float2 size = vLayerQuad.zw;
|
||||
outp.vPosition.x = position.x + aVertex.vPosition.x * size.x;
|
||||
outp.vPosition.y = position.y + aVertex.vPosition.y * size.y;
|
||||
|
||||
outp.vPosition = mul(mLayerTransform, outp.vPosition);
|
||||
outp.vPosition = outp.vPosition - vRenderTargetOffset;
|
||||
|
||||
outp.vPosition = mul(mProjection, outp.vPosition);
|
||||
|
||||
position = vTextureCoords.xy;
|
||||
size = vTextureCoords.zw;
|
||||
outp.vTexCoords.x = position.x + aVertex.vPosition.x * size.x;
|
||||
outp.vTexCoords.y = position.y + aVertex.vPosition.y * size.y;
|
||||
return outp;
|
||||
}
|
||||
|
||||
float4 RGBAShaderLinear(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
return tRGB.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) * fLayerOpacity;
|
||||
}
|
||||
|
||||
float4 RGBAShaderPoint(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
return tRGB.Sample(LayerTextureSamplerPoint, aVertex.vTexCoords) * fLayerOpacity;
|
||||
}
|
||||
|
||||
float4 RGBShaderLinear(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float4 result;
|
||||
result = tRGB.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords) * fLayerOpacity;
|
||||
result.a = fLayerOpacity;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 RGBShaderPoint(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float4 result;
|
||||
result = tRGB.Sample(LayerTextureSamplerPoint, aVertex.vTexCoords) * fLayerOpacity;
|
||||
result.a = fLayerOpacity;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 YCbCrShader(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float4 yuv;
|
||||
float4 color;
|
||||
|
||||
yuv.r = tCr.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords).r - 0.5;
|
||||
yuv.g = tY.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords).r - 0.0625;
|
||||
yuv.b = tCb.Sample(LayerTextureSamplerLinear, aVertex.vTexCoords).r - 0.5;
|
||||
|
||||
color.r = yuv.g * 1.164 + yuv.r * 1.596;
|
||||
color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b;
|
||||
color.b = yuv.g * 1.164 + yuv.b * 2.018;
|
||||
color.a = 1.0f;
|
||||
|
||||
return color * fLayerOpacity;
|
||||
}
|
||||
|
||||
float4 SolidColorShader(const VS_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
return fLayerColor;
|
||||
}
|
||||
|
||||
technique10 RenderRGBLayerPremul
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBShaderLinear() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderRGBLayerPremulPoint
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBShaderPoint() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderRGBALayerPremul
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBAShaderLinear() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderRGBALayerNonPremul
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( NonPremul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBAShaderLinear() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderRGBALayerPremulPoint
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBAShaderPoint() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderRGBALayerNonPremulPoint
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( NonPremul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, RGBAShaderPoint() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderYCbCrLayer
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, YCbCrShader() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 RenderSolidColorLayer
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( Premul, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, SolidColorShader() ) );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 GFX_LAYERMANAGERD3D10_H
|
||||
#define GFX_LAYERMANAGERD3D10_H
|
||||
|
||||
#include "Layers.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <d3d10_1.h>
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* This structure is used to pass rectangles to our shader constant. We can use
|
||||
* this for passing rectangular areas to SetVertexShaderConstant. In the format
|
||||
* of a 4 component float(x,y,width,height). Our vertex shader can then use
|
||||
* this to construct rectangular positions from the 0,0-1,1 quad that we source
|
||||
* it with.
|
||||
*/
|
||||
struct ShaderConstantRectD3D10
|
||||
{
|
||||
float mX, mY, mWidth, mHeight;
|
||||
ShaderConstantRectD3D10(float aX, float aY, float aWidth, float aHeight)
|
||||
: mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight)
|
||||
{ }
|
||||
|
||||
// For easy passing to SetVertexShaderConstantF.
|
||||
operator float* () { return &mX; }
|
||||
};
|
||||
|
||||
extern cairo_user_data_key_t gKeyD3D10Texture;
|
||||
|
||||
/*
|
||||
* This is the LayerManager used for Direct3D 9. For now this will render on
|
||||
* the main thread.
|
||||
*/
|
||||
class THEBES_API LayerManagerD3D10 : public LayerManager {
|
||||
public:
|
||||
LayerManagerD3D10(nsIWidget *aWidget);
|
||||
virtual ~LayerManagerD3D10();
|
||||
|
||||
/*
|
||||
* Initializes the layer manager, this is when the layer manager will
|
||||
* actually access the device and attempt to create the swap chain used
|
||||
* to draw to the window. If this method fails the device cannot be used.
|
||||
* This function is not threadsafe.
|
||||
*
|
||||
* \return True is initialization was succesful, false when it was not.
|
||||
*/
|
||||
bool Initialize();
|
||||
|
||||
/*
|
||||
* LayerManager implementation.
|
||||
*/
|
||||
virtual void SetRoot(Layer *aLayer);
|
||||
|
||||
void BeginTransaction();
|
||||
|
||||
void BeginTransactionWithTarget(gfxContext* aTarget);
|
||||
|
||||
struct CallbackInfo {
|
||||
DrawThebesLayerCallback Callback;
|
||||
void *CallbackData;
|
||||
};
|
||||
|
||||
void EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
const CallbackInfo &GetCallbackInfo() { return mCurrentCallbackInfo; }
|
||||
|
||||
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
|
||||
|
||||
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
|
||||
|
||||
virtual already_AddRefed<ImageLayer> CreateImageLayer();
|
||||
|
||||
virtual already_AddRefed<ColorLayer> CreateColorLayer();
|
||||
|
||||
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
|
||||
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
CreateOptimalSurface(const gfxIntSize &aSize,
|
||||
gfxASurface::gfxImageFormat imageFormat);
|
||||
|
||||
virtual LayersBackend GetBackendType() { return LAYERS_D3D10; }
|
||||
virtual void GetBackendName(nsAString& name) { name.AssignLiteral("Direct3D 10"); }
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
virtual const char* Name() const { return "D3D9"; }
|
||||
#endif // MOZ_LAYERS_HAVE_LOG
|
||||
|
||||
// Public helpers
|
||||
|
||||
ID3D10Device1 *device() const { return mDevice; }
|
||||
|
||||
ID3D10Effect *effect() const { return mEffect; }
|
||||
|
||||
void SetViewport(const nsIntSize &aViewport);
|
||||
const nsIntSize &GetViewport() { return mViewport; }
|
||||
|
||||
private:
|
||||
void SetupPipeline();
|
||||
void UpdateRenderTarget();
|
||||
void VerifyBufferSize();
|
||||
|
||||
void Render();
|
||||
|
||||
nsRefPtr<ID3D10Device1> mDevice;
|
||||
|
||||
nsRefPtr<ID3D10Effect> mEffect;
|
||||
nsRefPtr<ID3D10InputLayout> mInputLayout;
|
||||
nsRefPtr<ID3D10Buffer> mVertexBuffer;
|
||||
|
||||
nsRefPtr<ID3D10RenderTargetView> mRTView;
|
||||
|
||||
nsRefPtr<IDXGISwapChain> mSwapChain;
|
||||
|
||||
nsIWidget *mWidget;
|
||||
|
||||
CallbackInfo mCurrentCallbackInfo;
|
||||
|
||||
nsIntSize mViewport;
|
||||
|
||||
/*
|
||||
* Context target, NULL when drawing directly to our swap chain.
|
||||
*/
|
||||
nsRefPtr<gfxContext> mTarget;
|
||||
|
||||
/*
|
||||
* Copies the content of our backbuffer to the set transaction target.
|
||||
*/
|
||||
void PaintToTarget();
|
||||
};
|
||||
|
||||
/*
|
||||
* General information and tree management for OGL layers.
|
||||
*/
|
||||
class LayerD3D10
|
||||
{
|
||||
public:
|
||||
LayerD3D10(LayerManagerD3D10 *aManager);
|
||||
|
||||
virtual LayerD3D10 *GetFirstChildD3D10() { return nsnull; }
|
||||
|
||||
void SetFirstChild(LayerD3D10 *aParent);
|
||||
|
||||
virtual Layer* GetLayer() = 0;
|
||||
|
||||
/**
|
||||
* This will render a child layer to whatever render target is currently
|
||||
* active. aOpacity and aTransform will pass any 'carried' transformations
|
||||
* and/or opacity from the parent. This allows the parent to avoid
|
||||
* rendering to intermediate surfaces when possible.
|
||||
*/
|
||||
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform) = 0;
|
||||
virtual void Validate() {}
|
||||
|
||||
ID3D10Device1 *device() const { return mD3DManager->device(); }
|
||||
ID3D10Effect *effect() const { return mD3DManager->effect(); }
|
||||
|
||||
/* Called by the layer manager when it's destroyed */
|
||||
virtual void LayerManagerDestroyed() {}
|
||||
protected:
|
||||
LayerManagerD3D10 *mD3DManager;
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
|
||||
#endif /* GFX_LAYERMANAGERD3D9_H */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,339 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 "ThebesLayerD3D10.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
#include "gfxD2DSurface.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager)
|
||||
: ThebesLayer(aManager, NULL)
|
||||
, LayerD3D10(aManager)
|
||||
{
|
||||
mImplData = static_cast<LayerD3D10*>(this);
|
||||
}
|
||||
|
||||
ThebesLayerD3D10::~ThebesLayerD3D10()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retention threshold - amount of pixels intersection required to enable
|
||||
* layer content retention. This is a guesstimate. Profiling could be done to
|
||||
* figure out the optimal threshold.
|
||||
*/
|
||||
#define RETENTION_THRESHOLD 16384
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::SetVisibleRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
if (aRegion.IsEqual(mVisibleRegion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
nsIntRegion oldVisibleRegion = mVisibleRegion;
|
||||
ThebesLayer::SetVisibleRegion(aRegion);
|
||||
|
||||
if (!mTexture) {
|
||||
// If we don't need to retain content initialize lazily. This is good also
|
||||
// because we might get mIsOpaqueSurface set later than the first call to
|
||||
// SetVisibleRegion.
|
||||
return;
|
||||
}
|
||||
|
||||
VerifyContentType();
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> oldTexture = mTexture;
|
||||
|
||||
nsIntRect oldBounds = oldVisibleRegion.GetBounds();
|
||||
nsIntRect newBounds = mVisibleRegion.GetBounds();
|
||||
|
||||
CreateNewTexture(gfxIntSize(newBounds.width, newBounds.height));
|
||||
|
||||
// Old visible region will become the region that is covered by both the
|
||||
// old and the new visible region.
|
||||
oldVisibleRegion.And(oldVisibleRegion, mVisibleRegion);
|
||||
// No point in retaining parts which were not valid.
|
||||
oldVisibleRegion.And(oldVisibleRegion, mValidRegion);
|
||||
|
||||
nsIntRect largeRect = oldVisibleRegion.GetLargestRectangle();
|
||||
|
||||
// If we had no hardware texture before or have no retained area larger than
|
||||
// the retention threshold, we're not retaining and are done here. If our
|
||||
// texture creation failed this can mean a device reset is pending and we
|
||||
// should silently ignore the failure. In the future when device failures
|
||||
// are properly handled we should test for the type of failure and gracefully
|
||||
// handle different failures. See bug 569081.
|
||||
if (!oldTexture || !mTexture ||
|
||||
largeRect.width * largeRect.height < RETENTION_THRESHOLD) {
|
||||
mValidRegion.SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRegion retainedRegion;
|
||||
nsIntRegionRectIterator iter(oldVisibleRegion);
|
||||
const nsIntRect *r;
|
||||
while ((r = iter.Next())) {
|
||||
if (r->width * r->height > RETENTION_THRESHOLD) {
|
||||
// Calculate the retained rectangle's position on the old and the new
|
||||
// surface.
|
||||
D3D10_BOX box;
|
||||
box.left = r->x - oldBounds.x;
|
||||
box.top = r->y - oldBounds.y;
|
||||
box.right = box.left + r->width;
|
||||
box.bottom = box.top + r->height;
|
||||
box.back = 1.0f;
|
||||
box.front = 0;
|
||||
|
||||
device()->CopySubresourceRegion(mTexture, 0,
|
||||
r->x - newBounds.x,
|
||||
r->y - newBounds.y,
|
||||
0,
|
||||
oldTexture, 0,
|
||||
&box);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
retainedRegion.Or(retainedRegion, *r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Areas which were valid and were retained are still valid
|
||||
mValidRegion.And(mValidRegion, retainedRegion);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
mValidRegion.Sub(mValidRegion, aRegion);
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
|
||||
{
|
||||
if (!mTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
gfx3DMatrix transform = mTransform * aTransform;
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform._11, 0, 64);
|
||||
effect()->GetVariableByName("fLayerOpacity")->AsScalar()->SetFloat(GetOpacity() * aOpacity);
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
if (CanUseOpaqueSurface()) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBLayerPremul");
|
||||
} else {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
|
||||
}
|
||||
|
||||
|
||||
nsIntRegionRectIterator iter(mVisibleRegion);
|
||||
|
||||
const nsIntRect *iterRect;
|
||||
if (mSRView) {
|
||||
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView);
|
||||
}
|
||||
|
||||
while ((iterRect = iter.Next())) {
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)iterRect->x,
|
||||
(float)iterRect->y,
|
||||
(float)iterRect->width,
|
||||
(float)iterRect->height)
|
||||
);
|
||||
|
||||
effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)(iterRect->x - visibleRect.x) / (float)visibleRect.width,
|
||||
(float)(iterRect->y - visibleRect.y) / (float)visibleRect.height,
|
||||
(float)iterRect->width / (float)visibleRect.width,
|
||||
(float)iterRect->height / (float)visibleRect.height)
|
||||
);
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
device()->Draw(4, 0);
|
||||
}
|
||||
|
||||
// Set back to default.
|
||||
effect()->GetVariableByName("vTextureCoords")->AsVector()->
|
||||
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::Validate()
|
||||
{
|
||||
if (mVisibleRegion.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VerifyContentType();
|
||||
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
if (!mTexture) {
|
||||
CreateNewTexture(gfxIntSize(visibleRect.width, visibleRect.height));
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
if (!mValidRegion.IsEqual(mVisibleRegion)) {
|
||||
/* We use the bounds of the visible region because we draw the bounds of
|
||||
* this region when we draw this entire texture. We have to make sure that
|
||||
* the areas that aren't filled with content get their background drawn.
|
||||
* This is an issue for opaque surfaces, which otherwise won't get their
|
||||
* background painted.
|
||||
*/
|
||||
nsIntRegion region;
|
||||
region.Sub(mVisibleRegion, mValidRegion);
|
||||
|
||||
DrawRegion(region);
|
||||
|
||||
mValidRegion = mVisibleRegion;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::LayerManagerDestroyed()
|
||||
{
|
||||
mD3DManager = nsnull;
|
||||
}
|
||||
|
||||
Layer*
|
||||
ThebesLayerD3D10::GetLayer()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::VerifyContentType()
|
||||
{
|
||||
if (mD2DSurface) {
|
||||
gfxASurface::gfxContentType type = CanUseOpaqueSurface() ?
|
||||
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
|
||||
|
||||
if (type != mD2DSurface->GetContentType()) {
|
||||
mD2DSurface = new gfxD2DSurface(mTexture, type);
|
||||
|
||||
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
|
||||
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
|
||||
mD2DSurface = nsnull;
|
||||
return;
|
||||
}
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
HRESULT hr;
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
if (!mD2DSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> context = new gfxContext(mD2DSurface);
|
||||
|
||||
nsIntRegionRectIterator iter(aRegion);
|
||||
context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
|
||||
context->NewPath();
|
||||
const nsIntRect *iterRect;
|
||||
while ((iterRect = iter.Next())) {
|
||||
context->Rectangle(gfxRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
|
||||
}
|
||||
context->Clip();
|
||||
|
||||
if (mD2DSurface->GetContentType() != gfxASurface::CONTENT_COLOR) {
|
||||
context->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
context->Paint();
|
||||
context->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
}
|
||||
|
||||
LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||
cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::CreateNewTexture(const gfxIntSize &aSize)
|
||||
{
|
||||
if (aSize.width == 0 || aSize.height == 0) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
|
||||
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
|
||||
}
|
||||
|
||||
mD2DSurface = new gfxD2DSurface(mTexture, CanUseOpaqueSurface() ?
|
||||
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
|
||||
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
|
||||
mD2DSurface = nsnull;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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) 2009
|
||||
* 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 GFX_THEBESLAYERD3D10_H
|
||||
#define GFX_THEBESLAYERD3D10_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "LayerManagerD3D10.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ThebesLayerD3D10 : public ThebesLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
public:
|
||||
ThebesLayerD3D10(LayerManagerD3D10 *aManager);
|
||||
virtual ~ThebesLayerD3D10();
|
||||
|
||||
/* Layer implementation */
|
||||
void SetVisibleRegion(const nsIntRegion& aRegion);
|
||||
|
||||
/* ThebesLayer implementation */
|
||||
void InvalidateRegion(const nsIntRegion& aRegion);
|
||||
|
||||
/* LayerD3D10 implementation */
|
||||
Layer* GetLayer();
|
||||
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
|
||||
virtual void Validate();
|
||||
virtual void LayerManagerDestroyed();
|
||||
|
||||
private:
|
||||
/* Texture with our surface data */
|
||||
nsRefPtr<ID3D10Texture2D> mTexture;
|
||||
|
||||
/* Shader resource view for our texture */
|
||||
nsRefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
|
||||
/* Checks if our D2D surface has the right content type */
|
||||
void VerifyContentType();
|
||||
|
||||
/* This contains the thebes surface */
|
||||
nsRefPtr<gfxASurface> mD2DSurface;
|
||||
|
||||
/* Have a region of our layer drawn */
|
||||
void DrawRegion(const nsIntRegion &aRegion);
|
||||
|
||||
/* Create a new texture */
|
||||
void CreateNewTexture(const gfxIntSize &aSize);
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
#endif /* GFX_THEBESLAYERD3D10_H */
|
|
@ -279,6 +279,10 @@ ifdef MOZ_ENABLE_D3D9_LAYER
|
|||
DEFINES += -DMOZ_ENABLE_D3D9_LAYER
|
||||
endif
|
||||
|
||||
ifdef MOZ_ENABLE_D3D10_LAYER
|
||||
DEFINES += -DMOZ_ENABLE_D3D10_LAYER
|
||||
endif
|
||||
|
||||
ACDEFINES += -UWIN32_LEAN_AND_MEAN
|
||||
endif
|
||||
|
||||
|
|
|
@ -54,6 +54,14 @@ gfxD2DSurface::gfxD2DSurface(HANDLE handle, gfxContentType aContent)
|
|||
(cairo_content_t)aContent));
|
||||
}
|
||||
|
||||
gfxD2DSurface::gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent)
|
||||
{
|
||||
Init(cairo_d2d_surface_create_for_texture(
|
||||
gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
|
||||
texture,
|
||||
(cairo_content_t)aContent));
|
||||
}
|
||||
|
||||
gfxD2DSurface::gfxD2DSurface(cairo_surface_t *csurf)
|
||||
{
|
||||
Init(csurf, PR_TRUE);
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
struct ID3D10Texture2D;
|
||||
|
||||
class THEBES_API gfxD2DSurface : public gfxASurface {
|
||||
public:
|
||||
|
||||
|
@ -53,6 +55,8 @@ public:
|
|||
|
||||
gfxD2DSurface(HANDLE handle, gfxContentType aContent);
|
||||
|
||||
gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent);
|
||||
|
||||
gfxD2DSurface(cairo_surface_t *csurf);
|
||||
|
||||
virtual ~gfxD2DSurface();
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#ifdef MOZ_ENABLE_D3D9_LAYER
|
||||
#include "LayerManagerD3D9.h"
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_D3D10_LAYER
|
||||
#include "LayerManagerD3D10.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace layers;
|
||||
|
@ -16,4 +19,7 @@ void XXXNeverCalled_Layers()
|
|||
#ifdef MOZ_ENABLE_D3D9_LAYER
|
||||
LayerManagerD3D9(nsnull);
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_D3D10_LAYER
|
||||
LayerManagerD3D10(nsnull);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -122,6 +122,12 @@ TestShellCommandParent::RunCallback(const nsString& aResponse)
|
|||
JSObject* global = JS_GetGlobalObject(mCx);
|
||||
NS_ENSURE_TRUE(global, JS_FALSE);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mCx, global)) {
|
||||
NS_ERROR("Failed to enter compartment!");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
|
||||
NS_ENSURE_TRUE(str, JS_FALSE);
|
||||
|
||||
|
|
|
@ -609,6 +609,12 @@ ProcessFile(JSContext *cx,
|
|||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj)) {
|
||||
NS_ERROR("Failed to enter compartment!");
|
||||
return;
|
||||
}
|
||||
|
||||
JSScript* script =
|
||||
JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
|
||||
env->GetPrincipal());
|
||||
|
@ -630,6 +636,12 @@ ProcessFile(JSContext *cx,
|
|||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj)) {
|
||||
NS_ERROR("Failed to enter compartment!");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate lines until we get a 'compilable unit' - one that either
|
||||
* generates an error (before running out of source) or that compiles
|
||||
|
@ -1172,6 +1184,12 @@ XPCShellEnvironment::Init()
|
|||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, globalObj)) {
|
||||
NS_ERROR("Failed to enter compartment!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions)) {
|
||||
NS_ERROR("JS_DefineFunctions failed!");
|
||||
return false;
|
||||
|
@ -1204,6 +1222,12 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
|
|||
|
||||
JSObject* global = GetGlobalObject();
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mCx, global)) {
|
||||
NS_ERROR("Failed to enter compartment!");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSScript* script =
|
||||
JS_CompileUCScriptForPrincipals(mCx, global, GetPrincipal(),
|
||||
aString.get(), aString.Length(),
|
||||
|
|
|
@ -137,9 +137,15 @@ JetpackChild::Init(base::ProcessHandle aParentProcessHandle,
|
|||
JS_SetContextPrivate(mCx, this);
|
||||
JSObject* implGlobal =
|
||||
JS_NewCompartmentAndGlobalObject(mCx, const_cast<JSClass*>(&sGlobalClass), NULL);
|
||||
if (!implGlobal)
|
||||
return false;
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mCx, implGlobal))
|
||||
return false;
|
||||
|
||||
jsval ctypes;
|
||||
if (!implGlobal ||
|
||||
!JS_InitStandardClasses(mCx, implGlobal) ||
|
||||
if (!JS_InitStandardClasses(mCx, implGlobal) ||
|
||||
#ifdef BUILD_CTYPES
|
||||
!JS_InitCTypesClass(mCx, implGlobal) ||
|
||||
!JS_GetProperty(mCx, implGlobal, "ctypes", &ctypes) ||
|
||||
|
@ -173,6 +179,12 @@ JetpackChild::RecvSendMessage(const nsString& messageName,
|
|||
const nsTArray<Variant>& data)
|
||||
{
|
||||
JSAutoRequest request(mCx);
|
||||
|
||||
JSObject *global = JS_GetGlobalObject(mCx);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mCx, global))
|
||||
return false;
|
||||
|
||||
return JetpackActorCommon::RecvMessage(mCx, messageName, data, NULL);
|
||||
}
|
||||
|
||||
|
@ -181,9 +193,14 @@ JetpackChild::RecvEvalScript(const nsString& code)
|
|||
{
|
||||
JSAutoRequest request(mCx);
|
||||
|
||||
js::AutoValueRooter ignored(mCx);
|
||||
(void) JS_EvaluateUCScript(mCx, JS_GetGlobalObject(mCx), code.get(),
|
||||
code.Length(), "", 1, ignored.jsval_addr());
|
||||
JSObject *global = JS_GetGlobalObject(mCx);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mCx, global))
|
||||
return false;
|
||||
|
||||
jsval ignored;
|
||||
(void) JS_EvaluateUCScript(mCx, global, code.get(),
|
||||
code.Length(), "", 1, &ignored);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,10 @@ JetpackParent::SendMessage(const nsAString& aMessageName)
|
|||
|
||||
JSAutoRequest request(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, JS_GetGlobalObject(cx)))
|
||||
return false;
|
||||
|
||||
for (PRUint32 i = 1; i < argc; ++i)
|
||||
if (!jsval_to_Variant(cx, argv[i], data.AppendElement()))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
@ -162,6 +166,11 @@ JetpackParent::RecvSendMessage(const nsString& messageName,
|
|||
{
|
||||
AutoCXPusher cxp(mContext);
|
||||
JSAutoRequest request(mContext);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mContext, JS_GetGlobalObject(mContext)))
|
||||
return false;
|
||||
|
||||
return JetpackActorCommon::RecvMessage(mContext, messageName, data, NULL);
|
||||
}
|
||||
|
||||
|
@ -172,6 +181,11 @@ JetpackParent::AnswerCallMessage(const nsString& messageName,
|
|||
{
|
||||
AutoCXPusher cxp(mContext);
|
||||
JSAutoRequest request(mContext);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mContext, JS_GetGlobalObject(mContext)))
|
||||
return false;
|
||||
|
||||
return JetpackActorCommon::RecvMessage(mContext, messageName, data, results);
|
||||
}
|
||||
|
||||
|
@ -188,6 +202,10 @@ JetpackParent::CreateHandle(nsIVariant** aResult)
|
|||
|
||||
JSAutoRequest request(mContext);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(mContext, JS_GetGlobalObject(mContext)))
|
||||
return false;
|
||||
|
||||
JSObject* hobj = handle->ToJSObject(mContext);
|
||||
if (!hobj)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -139,17 +139,21 @@ _newJSDContext(JSRuntime* jsrt,
|
|||
|
||||
JS_BeginRequest(jsdc->dumbContext);
|
||||
|
||||
if( scopeobj )
|
||||
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, scopeobj);
|
||||
jsdc->glob = JS_NewGlobalObject(jsdc->dumbContext, &global_class);
|
||||
if( call )
|
||||
JS_LeaveCrossCompartmentCall(call);
|
||||
jsdc->glob = JS_NewCompartmentAndGlobalObject(jsdc->dumbContext, &global_class, NULL);
|
||||
|
||||
if( ! jsdc->glob )
|
||||
goto label_newJSDContext_failure;
|
||||
|
||||
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
|
||||
if( ! call )
|
||||
goto label_newJSDContext_failure;
|
||||
|
||||
if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
|
||||
goto label_newJSDContext_failure;
|
||||
|
||||
if( call )
|
||||
JS_LeaveCrossCompartmentCall(call);
|
||||
|
||||
JS_EndRequest(jsdc->dumbContext);
|
||||
|
||||
jsdc->data = NULL;
|
||||
|
|
|
@ -121,6 +121,7 @@ CPPSRCS = \
|
|||
jsarray.cpp \
|
||||
jsatom.cpp \
|
||||
jsbool.cpp \
|
||||
jsclone.cpp \
|
||||
jscntxt.cpp \
|
||||
jsdate.cpp \
|
||||
jsdbgapi.cpp \
|
||||
|
@ -177,6 +178,7 @@ INSTALLED_HEADERS = \
|
|||
jsbit.h \
|
||||
jsbool.h \
|
||||
jsclist.h \
|
||||
jsclone.h \
|
||||
jscntxt.h \
|
||||
jscompat.h \
|
||||
jsdate.h \
|
||||
|
@ -202,6 +204,7 @@ INSTALLED_HEADERS = \
|
|||
json.h \
|
||||
jsopcode.tbl \
|
||||
jsopcode.h \
|
||||
jsopcodeinlines.h \
|
||||
jsotypes.h \
|
||||
jsparse.h \
|
||||
jsproxy.h \
|
||||
|
@ -861,7 +864,7 @@ endif
|
|||
|
||||
ifdef ENABLE_TRACEJIT
|
||||
# Imacro compilation.
|
||||
$(CURDIR)/imacros.c.out: $(srcdir)/imacro_asm.py $(srcdir)/imacros.jsasm
|
||||
$(CURDIR)/imacros.c.out: $(srcdir)/imacro_asm.py $(srcdir)/imacros.jsasm jsopcode.tbl
|
||||
$(PYTHON) $< $(srcdir)/imacros.jsasm $(CURDIR)/imacros.c.out
|
||||
$(addsuffix .$(OBJ_SUFFIX),jstracer): $(CURDIR)/imacros.c.out
|
||||
|
||||
|
|
|
@ -37,6 +37,13 @@
|
|||
#include "X86Assembler.h"
|
||||
#include "AbstractMacroAssembler.h"
|
||||
|
||||
#if WTF_COMPILER_MSVC
|
||||
#if WTF_CPU_X86_64
|
||||
/* for __cpuid */
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
|
||||
|
@ -1078,12 +1085,17 @@ public:
|
|||
m_assembler.movzbl_rr(dest, dest);
|
||||
}
|
||||
|
||||
// As the SSE's were introduced in order, the presence of a later SSE implies
|
||||
// the presence of an earlier SSE. For example, SSE4_2 support implies SSE2 support.
|
||||
enum SSECheckState {
|
||||
NotCheckedSSE = 0,
|
||||
NoSSE = 1,
|
||||
HasSSE2 = 2,
|
||||
HasSSE4_1 = 3, // implies HasSSE2
|
||||
HasSSE4_2 = 4 // implies HasSSE4_1
|
||||
HasSSE = 2,
|
||||
HasSSE2 = 3,
|
||||
HasSSE3 = 4,
|
||||
HasSSSE3 = 5,
|
||||
HasSSE4_1 = 6,
|
||||
HasSSE4_2 = 7
|
||||
};
|
||||
|
||||
static SSECheckState getSSEState()
|
||||
|
@ -1116,7 +1128,6 @@ private:
|
|||
volatile int flags_ecx = 0;
|
||||
#if WTF_COMPILER_MSVC
|
||||
#if WTF_CPU_X86_64
|
||||
extern void __cpuid(int a[4], int b);
|
||||
int cpuinfo[4];
|
||||
|
||||
__cpuid(cpuinfo, 1);
|
||||
|
@ -1131,6 +1142,19 @@ private:
|
|||
}
|
||||
#endif
|
||||
#elif WTF_COMPILER_GCC
|
||||
#if WTF_CPU_X86_64
|
||||
asm (
|
||||
"movl $0x1, %%eax;"
|
||||
"pushq %%rbx;"
|
||||
"cpuid;"
|
||||
"popq %%rbx;"
|
||||
"movl %%ecx, %0;"
|
||||
"movl %%edx, %1;"
|
||||
: "=g" (flags_ecx), "=g" (flags_edx)
|
||||
:
|
||||
: "%eax", "%ecx", "%edx"
|
||||
);
|
||||
#else
|
||||
asm (
|
||||
"movl $0x1, %%eax;"
|
||||
"pushl %%ebx;"
|
||||
|
@ -1142,6 +1166,7 @@ private:
|
|||
:
|
||||
: "%eax", "%ecx", "%edx"
|
||||
);
|
||||
#endif
|
||||
#elif WTF_COMPILER_SUNPRO
|
||||
asm (
|
||||
"movl $0x1, %eax;"
|
||||
|
@ -1155,15 +1180,24 @@ private:
|
|||
: "%eax", "%ecx", "%edx"
|
||||
);
|
||||
#endif
|
||||
static const int SSEFeatureBit = 1 << 25;
|
||||
static const int SSE2FeatureBit = 1 << 26;
|
||||
static const int SSE3FeatureBit = 1 << 0;
|
||||
static const int SSSE3FeatureBit = 1 << 9;
|
||||
static const int SSE41FeatureBit = 1 << 19;
|
||||
static const int SSE42FeatureBit = 1 << 20;
|
||||
if (flags_ecx & SSE42FeatureBit)
|
||||
s_sseCheckState = HasSSE4_2;
|
||||
else if (flags_ecx & SSE41FeatureBit)
|
||||
s_sseCheckState = HasSSE4_1;
|
||||
else if (flags_ecx & SSSE3FeatureBit)
|
||||
s_sseCheckState = HasSSSE3;
|
||||
else if (flags_ecx & SSE3FeatureBit)
|
||||
s_sseCheckState = HasSSE3;
|
||||
else if (flags_edx & SSE2FeatureBit)
|
||||
s_sseCheckState = HasSSE2;
|
||||
else if (flags_edx & SSEFeatureBit)
|
||||
s_sseCheckState = HasSSE;
|
||||
else
|
||||
s_sseCheckState = NoSSE;
|
||||
}
|
||||
|
@ -1171,7 +1205,12 @@ private:
|
|||
#if WTF_CPU_X86
|
||||
#if WTF_PLATFORM_MAC
|
||||
|
||||
// All X86 Macs are guaranteed to support at least SSE2,
|
||||
// All X86 Macs are guaranteed to support at least SSE2
|
||||
static bool isSSEPresent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isSSE2Present()
|
||||
{
|
||||
return true;
|
||||
|
@ -1179,6 +1218,17 @@ private:
|
|||
|
||||
#else // PLATFORM(MAC)
|
||||
|
||||
static bool isSSEPresent()
|
||||
{
|
||||
if (s_sseCheckState == NotCheckedSSE) {
|
||||
setSSECheckState();
|
||||
}
|
||||
// Only check once.
|
||||
ASSERT(s_sseCheckState != NotCheckedSSE);
|
||||
|
||||
return s_sseCheckState >= HasSSE;
|
||||
}
|
||||
|
||||
static bool isSSE2Present()
|
||||
{
|
||||
if (s_sseCheckState == NotCheckedSSE) {
|
||||
|
@ -1202,6 +1252,27 @@ private:
|
|||
}
|
||||
|
||||
#endif
|
||||
static bool isSSE3Present()
|
||||
{
|
||||
if (s_sseCheckState == NotCheckedSSE) {
|
||||
setSSECheckState();
|
||||
}
|
||||
// Only check once.
|
||||
ASSERT(s_sseCheckState != NotCheckedSSE);
|
||||
|
||||
return s_sseCheckState >= HasSSE3;
|
||||
}
|
||||
|
||||
static bool isSSSE3Present()
|
||||
{
|
||||
if (s_sseCheckState == NotCheckedSSE) {
|
||||
setSSECheckState();
|
||||
}
|
||||
// Only check once.
|
||||
ASSERT(s_sseCheckState != NotCheckedSSE);
|
||||
|
||||
return s_sseCheckState >= HasSSSE3;
|
||||
}
|
||||
|
||||
static bool isSSE41Present()
|
||||
{
|
||||
|
|
|
@ -5318,6 +5318,10 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
|
|||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, jsfnObj))
|
||||
return;
|
||||
|
||||
// Assert that our CIFs agree.
|
||||
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj);
|
||||
JS_ASSERT(cif == &fninfo->mCIF);
|
||||
|
|
|
@ -339,3 +339,6 @@ MSG_DEF(JSMSG_CALLER_IS_STRICT, 256, 0, JSEXN_TYPEERR, "access to strict m
|
|||
MSG_DEF(JSMSG_NEED_DEBUG_MODE, 257, 0, JSEXN_ERR, "function can be called only in debug mode")
|
||||
MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
|
||||
MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")
|
||||
MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
|
||||
MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
|
||||
MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive object")
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "jsatom.h"
|
||||
#include "jsbool.h"
|
||||
#include "jsbuiltins.h"
|
||||
#include "jsclone.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsversion.h"
|
||||
#include "jsdate.h"
|
||||
|
@ -5245,6 +5246,55 @@ JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
|
|||
return js_FinishJSONParse(cx, jp, Valueify(reviver));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes, jsval *vp)
|
||||
{
|
||||
return ReadStructuredClone(cx, buf, nbytes, Valueify(vp));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp)
|
||||
{
|
||||
return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp)
|
||||
{
|
||||
JSAutoStructuredCloneBuffer buf(cx);
|
||||
return buf.write(v) && buf.read(vp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
|
||||
{
|
||||
rt->structuredCloneCallbacks = callbacks;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadPair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2)
|
||||
{
|
||||
return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
|
||||
{
|
||||
return r->input().readBytes(p, len);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WritePair(JSStructuredCloneWriter *w, uint32 tag, uint32 data)
|
||||
{
|
||||
return w->output().writePair(tag, data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
|
||||
{
|
||||
return w->output().writeBytes(p, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following determines whether C Strings are to be treated as UTF-8
|
||||
* or ISO-8859-1. For correct operation, it must be set prior to the
|
||||
|
|
106
js/src/jsapi.h
106
js/src/jsapi.h
|
@ -2844,6 +2844,112 @@ JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver);
|
|||
|
||||
/************************************************************************/
|
||||
|
||||
/* API for the HTML5 internal structured cloning algorithm. */
|
||||
|
||||
/* The maximum supported structured-clone serialization format version. */
|
||||
#define JS_STRUCTURED_CLONE_VERSION 1
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadStructuredClone(JSContext *cx, const uint64 *data, size_t nbytes, jsval *vp);
|
||||
|
||||
/* Note: On success, the caller is responsible for calling js_free(*datap). */
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **datap, size_t *nbytesp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* RAII sugar for JS_WriteStructuredClone. */
|
||||
class JSAutoStructuredCloneBuffer {
|
||||
JSContext *cx;
|
||||
uint64 *data_;
|
||||
size_t nbytes_;
|
||||
|
||||
public:
|
||||
explicit JSAutoStructuredCloneBuffer(JSContext *cx) : cx(cx), data_(NULL), nbytes_(0) {}
|
||||
~JSAutoStructuredCloneBuffer() { clear(); }
|
||||
|
||||
uint64 *data() const { return data_; }
|
||||
size_t nbytes() const { return nbytes_; }
|
||||
|
||||
void clear() {
|
||||
if (data_) {
|
||||
JS_free(cx, data_);
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adopt some memory. It will be automatically freed by the destructor.
|
||||
* data must have been allocated using JS_malloc.
|
||||
*/
|
||||
void adopt(uint64 *data, size_t nbytes) {
|
||||
clear();
|
||||
data_ = data;
|
||||
nbytes_ = nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the buffer so that it will not be automatically freed.
|
||||
* After this, the caller is responsible for calling JS_free(*datap).
|
||||
*/
|
||||
void steal(uint64 **datap, size_t *nbytesp) {
|
||||
*datap = data_;
|
||||
*nbytesp = nbytes_;
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
}
|
||||
|
||||
bool read(jsval *vp) const {
|
||||
JS_ASSERT(data_);
|
||||
return !!JS_ReadStructuredClone(cx, data_, nbytes_, vp);
|
||||
}
|
||||
|
||||
bool write(jsval v) {
|
||||
clear();
|
||||
bool ok = !!JS_WriteStructuredClone(cx, v, &data_, &nbytes_);
|
||||
if (!ok) {
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* API for implementing custom serialization behavior (for ImageData, File, etc.) */
|
||||
|
||||
/* The range of tag values the application may use for its own custom object types. */
|
||||
#define JS_SCTAG_USER_MIN ((uint32) 0xFFFF8000)
|
||||
#define JS_SCTAG_USER_MAX ((uint32) 0xFFFFFFFF)
|
||||
|
||||
#define JS_SCERR_RECURSION 0
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
WriteStructuredCloneOp write;
|
||||
StructuredCloneErrorOp reportError;
|
||||
};
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadPair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WritePair(JSStructuredCloneWriter *w, uint32 tag, uint32 data);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* Locale specific string conversion and error message callbacks.
|
||||
*/
|
||||
|
|
|
@ -2683,7 +2683,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
|
|||
return JS_FALSE;
|
||||
}
|
||||
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
|
||||
vp->setNumber(i);
|
||||
vp->setNumber(i);
|
||||
return JS_TRUE;
|
||||
}
|
||||
if (i == stop)
|
||||
|
|
|
@ -510,28 +510,36 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
|||
key = AtomEntryToKey(*p);
|
||||
} else {
|
||||
/*
|
||||
* Unless str is already allocated from the GC heap and flat, we have
|
||||
* to release state->lock as string construction is a complex
|
||||
* operation. For example, it can trigger GC which may rehash the table
|
||||
* and make the entry invalid.
|
||||
* Ensure that any atomized string lives only in the default
|
||||
* compartment.
|
||||
*/
|
||||
if (!(flags & ATOM_TMPSTR) && str->isFlat()) {
|
||||
bool needNewString = !!(flags & ATOM_TMPSTR) ||
|
||||
str->asCell()->compartment() != cx->runtime->defaultCompartment;
|
||||
|
||||
/*
|
||||
* Unless str is already comes from the default compartment and flat,
|
||||
* we have to relookup the key as the last ditch GC invoked from the
|
||||
* string allocation or OOM handling may unlock the default
|
||||
* compartment lock.
|
||||
*/
|
||||
if (!needNewString && str->isFlat()) {
|
||||
str->flatClearMutable();
|
||||
key = str;
|
||||
atoms.add(p, StringToInitialAtomEntry(key));
|
||||
} else {
|
||||
if (flags & ATOM_TMPSTR) {
|
||||
if (needNewString) {
|
||||
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
|
||||
|
||||
jschar *chars = str->chars();
|
||||
if (flags & ATOM_NOCOPY) {
|
||||
key = js_NewString(cx, str->flatChars(), str->flatLength());
|
||||
key = js_NewString(cx, chars, length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
/* Finish handing off chars to the GC'ed key string. */
|
||||
JS_ASSERT(flags & ATOM_TMPSTR);
|
||||
str->mChars = NULL;
|
||||
} else {
|
||||
key = js_NewStringCopyN(cx, str->flatChars(), str->flatLength());
|
||||
key = js_NewStringCopyN(cx, chars, length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
}
|
||||
|
@ -901,7 +909,7 @@ JSAutoAtomList::~JSAutoAtomList()
|
|||
if (table) {
|
||||
JS_HashTableDestroy(table);
|
||||
} else {
|
||||
JSHashEntry *hep = list;
|
||||
JSHashEntry *hep = list;
|
||||
while (hep) {
|
||||
JSHashEntry *next = hep->next;
|
||||
js_free_temp_entry(parser, hep, HT_FREE_ENTRY);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
@ -69,7 +69,6 @@ struct Cell {
|
|||
inline ArenaBitmap *bitmap() const;
|
||||
JS_ALWAYS_INLINE size_t cellIndex() const;
|
||||
|
||||
JS_ALWAYS_INLINE void mark(uint32 color) const;
|
||||
JS_ALWAYS_INLINE bool isMarked(uint32 color) const;
|
||||
JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color) const;
|
||||
|
||||
|
|
|
@ -0,0 +1,815 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* ***** 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 JavaScript structured data serialization.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jason Orendorff <jorendorff@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 "jsclone.h"
|
||||
#include "jsdate.h"
|
||||
#include "jsregexp.h"
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "jsregexpinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace js
|
||||
{
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext *cx, const Value &v, uint64 **bufp, size_t *nbytesp)
|
||||
{
|
||||
SCOutput out(cx);
|
||||
JSStructuredCloneWriter w(out);
|
||||
return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp);
|
||||
}
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp)
|
||||
{
|
||||
SCInput in(cx, data, nbytes);
|
||||
JSStructuredCloneReader r(in);
|
||||
return r.read(vp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum StructuredDataType {
|
||||
/* Structured data types provided by the engine */
|
||||
SCTAG_FLOAT_MAX = 0xFFF00000,
|
||||
SCTAG_NULL = 0xFFFF0000,
|
||||
SCTAG_UNDEFINED,
|
||||
SCTAG_BOOLEAN,
|
||||
SCTAG_INDEX,
|
||||
SCTAG_STRING,
|
||||
SCTAG_DATE_OBJECT,
|
||||
SCTAG_REGEXP_OBJECT,
|
||||
SCTAG_ARRAY_OBJECT,
|
||||
SCTAG_OBJECT_OBJECT,
|
||||
SCTAG_ARRAY_BUFFER_OBJECT,
|
||||
SCTAG_TYPED_ARRAY_MIN = 0xFFFF0100,
|
||||
SCTAG_TYPED_ARRAY_MAX = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_MAX - 1,
|
||||
SCTAG_END_OF_BUILTIN_TYPES
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
|
||||
JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX);
|
||||
|
||||
static uint8_t
|
||||
SwapBytes(uint8_t u)
|
||||
{
|
||||
return u;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
SwapBytes(uint16_t u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x00ff) << 8) | ((u & 0xff00) >> 8);
|
||||
#else
|
||||
return u;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
SwapBytes(uint32_t u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x000000ffU) << 24) |
|
||||
((u & 0x0000ff00U) << 8) |
|
||||
((u & 0x00ff0000U) >> 8) |
|
||||
((u & 0xff000000U) >> 24);
|
||||
#else
|
||||
return u;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
SwapBytes(uint64_t u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x00000000000000ffLLU) << 56) |
|
||||
((u & 0x000000000000ff00LLU) << 40) |
|
||||
((u & 0x0000000000ff0000LLU) << 24) |
|
||||
((u & 0x00000000ff000000LLU) << 8) |
|
||||
((u & 0x000000ff00000000LLU) >> 8) |
|
||||
((u & 0x0000ff0000000000LLU) >> 24) |
|
||||
((u & 0x00ff000000000000LLU) >> 40) |
|
||||
((u & 0xff00000000000000LLU) >> 56);
|
||||
#else
|
||||
return u;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::eof()
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "truncated");
|
||||
return false;
|
||||
}
|
||||
|
||||
SCInput::SCInput(JSContext *cx, const uint64_t *data, size_t nbytes)
|
||||
: cx(cx), point(data), end(data + nbytes / 8)
|
||||
{
|
||||
JS_ASSERT((uintptr_t(data) & 7) == 0);
|
||||
JS_ASSERT((nbytes & 7) == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::read(uint64_t *p)
|
||||
{
|
||||
if (point == end)
|
||||
return eof();
|
||||
*p = SwapBytes(*point++);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readPair(uint32_t *tagp, uint32_t *datap)
|
||||
{
|
||||
uint64_t u;
|
||||
bool ok = read(&u);
|
||||
if (ok) {
|
||||
*tagp = uint32_t(u >> 32);
|
||||
*datap = uint32_t(u);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readDouble(jsdouble *p)
|
||||
{
|
||||
union {
|
||||
uint64_t u;
|
||||
jsdouble d;
|
||||
} pun;
|
||||
if (!read(&pun.u))
|
||||
return false;
|
||||
*p = JS_CANONICALIZE_NAN(pun.d);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
SCInput::readArray(T *p, size_t nelems)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
|
||||
|
||||
/*
|
||||
* Fail if nelems is so huge as to make JS_HOWMANY overflow or if nwords is
|
||||
* larger than the remaining data.
|
||||
*/
|
||||
size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
|
||||
if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems || nwords > size_t(end - point))
|
||||
return eof();
|
||||
|
||||
if (sizeof(T) == 1) {
|
||||
memcpy(p, point, nelems);
|
||||
} else {
|
||||
const T *q = (const T *) point;
|
||||
const T *qend = q + nelems;
|
||||
while (q != qend)
|
||||
*p++ = SwapBytes(*q++);
|
||||
}
|
||||
point += nwords;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readBytes(void *p, size_t nbytes)
|
||||
{
|
||||
return readArray((uint8_t *) p, nbytes);
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readChars(jschar *p, size_t nchars)
|
||||
{
|
||||
JS_ASSERT(sizeof(jschar) == sizeof(uint16_t));
|
||||
return readArray((uint16_t *) p, nchars);
|
||||
}
|
||||
|
||||
SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {}
|
||||
|
||||
bool
|
||||
SCOutput::write(uint64_t u)
|
||||
{
|
||||
return buf.append(SwapBytes(u));
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
PairToUInt64(uint32_t tag, uint32_t data)
|
||||
{
|
||||
return uint64_t(data) | (uint64_t(tag) << 32);
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writePair(uint32_t tag, uint32_t data)
|
||||
{
|
||||
/*
|
||||
* As it happens, the tag word appears after the data word in the output.
|
||||
* This is because exponents occupy the last 2 bytes of jsdoubles on the
|
||||
* little-endian platforms we care most about.
|
||||
*
|
||||
* For example, JSVAL_TRUE is written using writePair(SCTAG_BOOLEAN, 1).
|
||||
* PairToUInt64 produces the number 0xFFFF000200000001.
|
||||
* That is written out as the bytes 01 00 00 00 02 00 FF FF.
|
||||
*/
|
||||
return write(PairToUInt64(tag, data));
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
ReinterpretDoubleAsUInt64(jsdouble d)
|
||||
{
|
||||
union {
|
||||
jsdouble d;
|
||||
uint64_t u;
|
||||
} pun;
|
||||
pun.d = d;
|
||||
return pun.u;
|
||||
}
|
||||
|
||||
static inline jsdouble
|
||||
ReinterpretUInt64AsDouble(uint64_t u)
|
||||
{
|
||||
union {
|
||||
uint64_t u;
|
||||
jsdouble d;
|
||||
} pun;
|
||||
pun.u = u;
|
||||
return pun.d;
|
||||
}
|
||||
|
||||
static inline jsdouble
|
||||
ReinterpretPairAsDouble(uint32_t tag, uint32_t data)
|
||||
{
|
||||
return ReinterpretUInt64AsDouble(PairToUInt64(tag, data));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsNonCanonicalizedNaN(jsdouble d)
|
||||
{
|
||||
return ReinterpretDoubleAsUInt64(d) != ReinterpretDoubleAsUInt64(JS_CANONICALIZE_NAN(d));
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writeDouble(jsdouble d)
|
||||
{
|
||||
JS_ASSERT(!IsNonCanonicalizedNaN(d));
|
||||
return write(ReinterpretDoubleAsUInt64(d));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
SCOutput::writeArray(const T *p, size_t nelems)
|
||||
{
|
||||
JS_ASSERT(8 % sizeof(T) == 0);
|
||||
JS_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
|
||||
|
||||
if (nelems == 0)
|
||||
return true;
|
||||
|
||||
if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems) {
|
||||
js_ReportAllocationOverflow(context());
|
||||
return false;
|
||||
}
|
||||
uint64_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
|
||||
size_t start = buf.length();
|
||||
if (!buf.growByUninitialized(nwords))
|
||||
return false;
|
||||
|
||||
buf.back() = 0; /* zero-pad to an 8-byte boundary */
|
||||
|
||||
T *q = (T *) &buf[start];
|
||||
if (sizeof(T) == 1) {
|
||||
memcpy(q, p, nelems);
|
||||
} else {
|
||||
const T *pend = p + nelems;
|
||||
while (p != pend)
|
||||
*q++ = SwapBytes(*p++);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writeBytes(const void *p, size_t nbytes)
|
||||
{
|
||||
return writeArray((const uint8_t *) p, nbytes);
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writeChars(const jschar *p, size_t nchars)
|
||||
{
|
||||
JS_ASSERT(sizeof(jschar) == sizeof(uint16_t));
|
||||
return writeArray((const uint16_t *) p, nchars);
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::extractBuffer(uint64_t **datap, size_t *sizep)
|
||||
{
|
||||
*sizep = buf.length() * sizeof(uint64_t);
|
||||
return (*datap = buf.extractRawBuffer()) != NULL;
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeString(JSString *str)
|
||||
{
|
||||
const jschar *chars;
|
||||
size_t length;
|
||||
str->getCharsAndLength(chars, length);
|
||||
return out.writePair(SCTAG_STRING, uint32_t(length)) && out.writeChars(chars, length);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeId(jsid id)
|
||||
{
|
||||
if (JSID_IS_INT(id))
|
||||
return out.writePair(SCTAG_INDEX, uint32_t(JSID_TO_INT(id)));
|
||||
JS_ASSERT(JSID_IS_STRING(id));
|
||||
return writeString(JSID_TO_STRING(id));
|
||||
}
|
||||
|
||||
inline void
|
||||
JSStructuredCloneWriter::checkStack()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* To avoid making serialization O(n^2), limit stack-checking at 10. */
|
||||
const size_t MAX = 10;
|
||||
|
||||
size_t limit = JS_MIN(counts.length(), MAX);
|
||||
JS_ASSERT(objs.length() == counts.length());
|
||||
size_t total = 0;
|
||||
for (size_t i = 0; i < limit; i++) {
|
||||
JS_ASSERT(total + counts[i] >= total);
|
||||
total += counts[i];
|
||||
}
|
||||
if (counts.length() <= MAX)
|
||||
JS_ASSERT(total == ids.length());
|
||||
else
|
||||
JS_ASSERT(total <= ids.length());
|
||||
|
||||
JS_ASSERT(memory.count() == objs.length());
|
||||
size_t j = objs.length();
|
||||
for (size_t i = 0; i < limit; i++)
|
||||
JS_ASSERT(memory.has(&objs[--j].toObject()));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
ArrayTypeToTag(uint32_t type)
|
||||
{
|
||||
/*
|
||||
* As long as these are all true, we can just add. Note that for backward
|
||||
* compatibility, the tags cannot change. So if the ArrayType type codes
|
||||
* change, this function and TagToArrayType will have to do more work.
|
||||
*/
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_INT8 == 0);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_UINT8 == 1);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_INT16 == 2);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_UINT16 == 3);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_INT32 == 4);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_UINT32 == 5);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_FLOAT32 == 6);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_FLOAT64 == 7);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_UINT8_CLAMPED == 8);
|
||||
JS_STATIC_ASSERT(TypedArray::TYPE_MAX == TypedArray::TYPE_UINT8_CLAMPED + 1);
|
||||
|
||||
JS_ASSERT(type < TypedArray::TYPE_MAX);
|
||||
return SCTAG_TYPED_ARRAY_MIN + type;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
TagToArrayType(uint32_t tag)
|
||||
{
|
||||
JS_ASSERT(SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX);
|
||||
return tag - SCTAG_TYPED_ARRAY_MIN;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
|
||||
{
|
||||
TypedArray *arr = TypedArray::fromJSObject(obj);
|
||||
if (!out.writePair(ArrayTypeToTag(arr->type), arr->length))
|
||||
return false;
|
||||
|
||||
switch (arr->type) {
|
||||
case TypedArray::TYPE_INT8:
|
||||
case TypedArray::TYPE_UINT8:
|
||||
case TypedArray::TYPE_UINT8_CLAMPED:
|
||||
return out.writeArray((const uint8_t *) arr->data, arr->length);
|
||||
case TypedArray::TYPE_INT16:
|
||||
case TypedArray::TYPE_UINT16:
|
||||
return out.writeArray((const uint16_t *) arr->data, arr->length);
|
||||
case TypedArray::TYPE_INT32:
|
||||
case TypedArray::TYPE_UINT32:
|
||||
case TypedArray::TYPE_FLOAT32:
|
||||
return out.writeArray((const uint32_t *) arr->data, arr->length);
|
||||
case TypedArray::TYPE_FLOAT64:
|
||||
return out.writeArray((const uint64_t *) arr->data, arr->length);
|
||||
default:
|
||||
JS_NOT_REACHED("unknown TypedArray type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj)
|
||||
{
|
||||
ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj);
|
||||
return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, abuf->byteLength) &&
|
||||
out.writeBytes(abuf->data, abuf->byteLength);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::startObject(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArray() || obj->isObject());
|
||||
|
||||
/* Fail if obj is already on the stack. */
|
||||
HashSet<JSObject *>::AddPtr p = memory.lookupForAdd(obj);
|
||||
if (p) {
|
||||
JSContext *cx = context();
|
||||
const JSStructuredCloneCallbacks *cb = cx->runtime->structuredCloneCallbacks;
|
||||
if (cb && cb->reportError)
|
||||
cb->reportError(cx, JS_SCERR_RECURSION);
|
||||
else
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_RECURSION);
|
||||
return false;
|
||||
}
|
||||
if (!memory.add(p, obj))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Get enumerable property ids and put them in reverse order so that they
|
||||
* will come off the stack in forward order.
|
||||
*/
|
||||
size_t initialLength = ids.length();
|
||||
if (!GetPropertyNames(context(), obj, JSITER_OWNONLY, &ids))
|
||||
return false;
|
||||
jsid *begin = ids.begin() + initialLength, *end = ids.end();
|
||||
size_t count = size_t(end - begin);
|
||||
Reverse(begin, end);
|
||||
|
||||
/* Push obj and count to the stack. */
|
||||
if (!objs.append(ObjectValue(*obj)) || !counts.append(count))
|
||||
return false;
|
||||
checkStack();
|
||||
|
||||
/* Write the header for obj. */
|
||||
return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::startWrite(const js::Value &v)
|
||||
{
|
||||
if (v.isString()) {
|
||||
return writeString(v.toString());
|
||||
} else if (v.isNumber()) {
|
||||
return out.writeDouble(v.toNumber());
|
||||
} else if (v.isBoolean()) {
|
||||
return out.writePair(SCTAG_BOOLEAN, v.toBoolean());
|
||||
} else if (v.isNull()) {
|
||||
return out.writePair(SCTAG_NULL, 0);
|
||||
} else if (v.isUndefined()) {
|
||||
return out.writePair(SCTAG_UNDEFINED, 0);
|
||||
} else if (v.isObject()) {
|
||||
JSObject *obj = &v.toObject();
|
||||
if (obj->isRegExp()) {
|
||||
RegExp *re = RegExp::extractFrom(obj);
|
||||
return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
|
||||
writeString(re->getSource());
|
||||
} else if (obj->isDate()) {
|
||||
jsdouble d = js_DateGetMsecSinceEpoch(context(), obj);
|
||||
return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d);
|
||||
} else if (obj->isObject() || obj->isArray()) {
|
||||
return startObject(obj);
|
||||
} else if (js_IsTypedArray(obj)) {
|
||||
return writeTypedArray(obj);
|
||||
} else if (js_IsArrayBuffer(obj) && ArrayBuffer::fromJSObject(obj)) {
|
||||
return writeArrayBuffer(obj);
|
||||
}
|
||||
/* else fall through */
|
||||
}
|
||||
|
||||
/*
|
||||
* v is either an object or some strange value like JSVAL_HOLE. Even in the
|
||||
* latter case, we call the write op anyway, to let the application throw
|
||||
* the NOT_SUPPORTED_ERR exception.
|
||||
*/
|
||||
JSContext *cx = context();
|
||||
JSRuntime *rt = cx->runtime;
|
||||
if (rt->structuredCloneCallbacks)
|
||||
return rt->structuredCloneCallbacks->write(cx, this, Jsvalify(v));
|
||||
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_UNSUPPORTED_TYPE);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::write(const Value &v)
|
||||
{
|
||||
if (!startWrite(v))
|
||||
return false;
|
||||
|
||||
while (!counts.empty()) {
|
||||
JSObject *obj = &objs.back().toObject();
|
||||
if (counts.back()) {
|
||||
counts.back()--;
|
||||
jsid id = ids.back();
|
||||
ids.popBack();
|
||||
checkStack();
|
||||
if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
|
||||
/*
|
||||
* If obj still has an own property named id, write it out.
|
||||
* The cost of re-checking could be avoided by using
|
||||
* NativeIterators.
|
||||
*/
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
if (!js_HasOwnProperty(context(), obj->getOps()->lookupProperty, obj, id,
|
||||
&obj2, &prop)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prop) {
|
||||
obj2->dropProperty(context(), prop);
|
||||
|
||||
Value val;
|
||||
if (!writeId(id) || !obj->getProperty(context(), id, &val) || !startWrite(val))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.writePair(SCTAG_NULL, 0);
|
||||
memory.remove(obj);
|
||||
objs.popBack();
|
||||
counts.popBack();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class Chars {
|
||||
JSContext *cx;
|
||||
jschar *p;
|
||||
public:
|
||||
Chars() : p(NULL) {}
|
||||
~Chars() { if (p) cx->free(p); }
|
||||
|
||||
bool allocate(JSContext *cx, size_t len) {
|
||||
JS_ASSERT(!p);
|
||||
p = (jschar *) cx->malloc(len * sizeof(jschar));
|
||||
this->cx = cx;
|
||||
return p != NULL;
|
||||
}
|
||||
jschar *get() { return p; }
|
||||
void forget() { p = NULL; }
|
||||
};
|
||||
|
||||
JSString *
|
||||
JSStructuredCloneReader::readString(uint32_t nchars)
|
||||
{
|
||||
if (nchars > JSString::MAX_LENGTH) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
|
||||
"string length");
|
||||
return NULL;
|
||||
}
|
||||
Chars chars;
|
||||
if (!chars.allocate(context(), nchars) || !in.readChars(chars.get(), nchars))
|
||||
return NULL;
|
||||
JSString *str = js_NewString(context(), chars.get(), nchars);
|
||||
if (str)
|
||||
chars.forget();
|
||||
return str;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp)
|
||||
{
|
||||
uint32_t atype = TagToArrayType(tag);
|
||||
JSObject *obj = js_CreateTypedArray(context(), atype, nelems);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
|
||||
TypedArray *arr = TypedArray::fromJSObject(obj);
|
||||
JS_ASSERT(arr->length == nelems);
|
||||
JS_ASSERT(arr->type == atype);
|
||||
switch (atype) {
|
||||
case TypedArray::TYPE_INT8:
|
||||
case TypedArray::TYPE_UINT8:
|
||||
case TypedArray::TYPE_UINT8_CLAMPED:
|
||||
return in.readArray((uint8_t *) arr->data, nelems);
|
||||
case TypedArray::TYPE_INT16:
|
||||
case TypedArray::TYPE_UINT16:
|
||||
return in.readArray((uint16_t *) arr->data, nelems);
|
||||
case TypedArray::TYPE_INT32:
|
||||
case TypedArray::TYPE_UINT32:
|
||||
case TypedArray::TYPE_FLOAT32:
|
||||
return in.readArray((uint32_t *) arr->data, nelems);
|
||||
case TypedArray::TYPE_FLOAT64:
|
||||
return in.readArray((uint64_t *) arr->data, nelems);
|
||||
default:
|
||||
JS_NOT_REACHED("unknown TypedArray type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
|
||||
{
|
||||
JSObject *obj = js_CreateArrayBuffer(context(), nbytes);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj);
|
||||
JS_ASSERT(abuf->byteLength == nbytes);
|
||||
return in.readArray((uint8_t *) abuf->data, nbytes);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::startRead(Value *vp)
|
||||
{
|
||||
uint32_t tag, data;
|
||||
|
||||
if (!in.readPair(&tag, &data))
|
||||
return false;
|
||||
switch (tag) {
|
||||
case SCTAG_NULL:
|
||||
vp->setNull();
|
||||
break;
|
||||
|
||||
case SCTAG_UNDEFINED:
|
||||
vp->setUndefined();
|
||||
break;
|
||||
|
||||
case SCTAG_BOOLEAN:
|
||||
vp->setBoolean(!!data);
|
||||
break;
|
||||
|
||||
case SCTAG_STRING: {
|
||||
JSString *str = readString(data);
|
||||
if (!str)
|
||||
return false;
|
||||
vp->setString(str);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_DATE_OBJECT: {
|
||||
jsdouble d;
|
||||
if (!in.readDouble(&d))
|
||||
return false;
|
||||
JSObject *obj = js_NewDateObjectMsec(context(), d);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_REGEXP_OBJECT: {
|
||||
uint32_t tag2, nchars;
|
||||
if (!in.readPair(&tag2, &nchars))
|
||||
return false;
|
||||
if (tag2 != SCTAG_STRING) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
|
||||
"regexp");
|
||||
return false;
|
||||
}
|
||||
JSString *str = readString(nchars);
|
||||
if (!str)
|
||||
return false;
|
||||
const jschar *chars;
|
||||
size_t length;
|
||||
str->getCharsAndLength(chars, length);
|
||||
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_ARRAY_OBJECT:
|
||||
case SCTAG_OBJECT_OBJECT: {
|
||||
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
|
||||
? js_NewArrayObject(context(), 0, NULL)
|
||||
: NewBuiltinClassInstance(context(), &js_ObjectClass);
|
||||
if (!obj || !objs.append(ObjectValue(*obj)))
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_ARRAY_BUFFER_OBJECT:
|
||||
return readArrayBuffer(data, vp);
|
||||
|
||||
default:
|
||||
if (tag <= SCTAG_FLOAT_MAX) {
|
||||
jsdouble d = ReinterpretPairAsDouble(tag, data);
|
||||
if (IsNonCanonicalizedNaN(d)) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "unrecognized NaN");
|
||||
return false;
|
||||
}
|
||||
vp->setNumber(d);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX)
|
||||
return readTypedArray(tag, data, vp);
|
||||
|
||||
JSRuntime *rt = context()->runtime;
|
||||
if (!rt->structuredCloneCallbacks) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
|
||||
"unsupported type");
|
||||
return false;
|
||||
}
|
||||
return rt->structuredCloneCallbacks->read(context(), this, tag, data, Jsvalify(vp));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::readId(jsid *idp)
|
||||
{
|
||||
uint32_t tag, data;
|
||||
if (!in.readPair(&tag, &data))
|
||||
return false;
|
||||
|
||||
if (tag == SCTAG_INDEX) {
|
||||
*idp = INT_TO_JSID(int32_t(data));
|
||||
return true;
|
||||
}
|
||||
if (tag == SCTAG_STRING) {
|
||||
JSString *str = readString(data);
|
||||
if (!str)
|
||||
return false;
|
||||
JSAtom *atom = js_AtomizeString(context(), str, 0);
|
||||
if (!atom)
|
||||
return false;
|
||||
*idp = ATOM_TO_JSID(atom);
|
||||
return true;
|
||||
}
|
||||
if (tag == SCTAG_NULL) {
|
||||
*idp = JSID_VOID;
|
||||
return true;
|
||||
}
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "id");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::read(Value *vp)
|
||||
{
|
||||
if (!startRead(vp))
|
||||
return false;
|
||||
|
||||
while (objs.length() != 0) {
|
||||
JSObject *obj = &objs.back().toObject();
|
||||
|
||||
jsid id;
|
||||
if (!readId(&id))
|
||||
return false;
|
||||
|
||||
if (JSID_IS_VOID(id)) {
|
||||
objs.popBack();
|
||||
} else {
|
||||
Value v;
|
||||
if (!startRead(&v) || !obj->defineProperty(context(), id, v))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* ***** 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 JavaScript structured data serialization.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jason Orendorff <jorendorff@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 jsclone_h___
|
||||
#define jsclone_h___
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsvalue.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp);
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp);
|
||||
|
||||
struct SCOutput {
|
||||
public:
|
||||
explicit SCOutput(JSContext *cx);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool write(uint64_t u);
|
||||
bool writePair(uint32_t tag, uint32_t data);
|
||||
bool writeDouble(jsdouble d);
|
||||
bool writeBytes(const void *p, size_t nbytes);
|
||||
bool writeChars(const jschar *p, size_t nchars);
|
||||
|
||||
template <class T>
|
||||
bool writeArray(const T *p, size_t nbytes);
|
||||
|
||||
bool extractBuffer(uint64_t **datap, size_t *sizep);
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
js::Vector<uint64_t> buf;
|
||||
};
|
||||
|
||||
struct SCInput {
|
||||
public:
|
||||
SCInput(JSContext *cx, const uint64_t *data, size_t nbytes);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool read(uint64_t *p);
|
||||
bool readPair(uint32_t *tagp, uint32_t *datap);
|
||||
bool readDouble(jsdouble *p);
|
||||
bool readBytes(void *p, size_t nbytes);
|
||||
bool readChars(jschar *p, size_t nchars);
|
||||
|
||||
template <class T>
|
||||
bool readArray(T *p, size_t nelems);
|
||||
|
||||
private:
|
||||
bool eof();
|
||||
|
||||
void staticAssertions() {
|
||||
JS_STATIC_ASSERT(sizeof(jschar) == 2);
|
||||
JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(jsdouble) == 8);
|
||||
}
|
||||
|
||||
JSContext *cx;
|
||||
const uint64_t *point;
|
||||
const uint64_t *end;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct JSStructuredCloneReader {
|
||||
public:
|
||||
explicit JSStructuredCloneReader(js::SCInput &in)
|
||||
: in(in), objs(in.context()) {}
|
||||
|
||||
js::SCInput &input() { return in; }
|
||||
bool read(js::Value *vp);
|
||||
|
||||
private:
|
||||
JSContext *context() { return in.context(); }
|
||||
|
||||
JSString *readString(uint32_t nchars);
|
||||
bool readTypedArray(uint32_t tag, uint32_t nelems, js::Value *vp);
|
||||
bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
|
||||
bool readId(jsid *idp);
|
||||
bool startRead(js::Value *vp);
|
||||
|
||||
js::SCInput ∈
|
||||
|
||||
// Stack of objects with properties remaining to be read.
|
||||
js::AutoValueVector objs;
|
||||
};
|
||||
|
||||
struct JSStructuredCloneWriter {
|
||||
public:
|
||||
explicit JSStructuredCloneWriter(js::SCOutput &out)
|
||||
: out(out), objs(out.context()), counts(out.context()), ids(out.context()),
|
||||
memory(out.context()) {}
|
||||
|
||||
bool init() { return memory.init(); }
|
||||
|
||||
bool write(const js::Value &v);
|
||||
|
||||
js::SCOutput &output() { return out; }
|
||||
|
||||
private:
|
||||
JSContext *context() { return out.context(); }
|
||||
|
||||
bool writeString(JSString *str);
|
||||
bool writeId(jsid id);
|
||||
bool writeArrayBuffer(JSObject *obj);
|
||||
bool writeTypedArray(JSObject *obj);
|
||||
bool startObject(JSObject *obj);
|
||||
bool startWrite(const js::Value &v);
|
||||
|
||||
inline void checkStack();
|
||||
|
||||
js::SCOutput &out;
|
||||
|
||||
// Stack of objects with properties remaining to be written.
|
||||
js::AutoValueVector objs;
|
||||
|
||||
// counts[i] is the number of properties of objs[i] remaining to be written.
|
||||
// counts.length() == objs.length() and sum(counts) == ids.length().
|
||||
js::Vector<size_t> counts;
|
||||
|
||||
// Ids of properties remaining to be written.
|
||||
js::AutoIdVector ids;
|
||||
|
||||
// The "memory" list described in the HTML5 internal structured cloning algorithm.
|
||||
// memory has the same elements as objs.
|
||||
js::HashSet<JSObject *> memory;
|
||||
};
|
||||
|
||||
#endif /* jsclone_h___ */
|
|
@ -434,7 +434,7 @@ void
|
|||
FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
|
||||
{
|
||||
JS_ASSERT(prev);
|
||||
JS_ASSERT(curpc == prev->savedpc_);
|
||||
JS_ASSERT(curpc == curfp->pc(cx, fp));
|
||||
JS_ASSERT(fp == curseg->getInitialFrame());
|
||||
|
||||
/*
|
||||
|
@ -2035,16 +2035,10 @@ void
|
|||
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
|
||||
{
|
||||
JS_ASSERT(regs != &newregs);
|
||||
if (hasActiveSegment()) {
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
if (hasActiveSegment())
|
||||
currentSegment->suspend(regs);
|
||||
}
|
||||
newseg->setPreviousInContext(currentSegment);
|
||||
currentSegment = newseg;
|
||||
#ifdef DEBUG
|
||||
newregs.fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
setCurrentRegs(&newregs);
|
||||
newseg->joinContext(this, newregs.fp);
|
||||
}
|
||||
|
@ -2054,7 +2048,6 @@ JSContext::popSegmentAndFrame()
|
|||
{
|
||||
JS_ASSERT(currentSegment->maybeContext() == this);
|
||||
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
currentSegment->leaveContext();
|
||||
currentSegment = currentSegment->getPreviousInContext();
|
||||
if (currentSegment) {
|
||||
|
@ -2063,9 +2056,6 @@ JSContext::popSegmentAndFrame()
|
|||
} else {
|
||||
setCurrentRegs(currentSegment->getSuspendedRegs());
|
||||
currentSegment->resume();
|
||||
#ifdef DEBUG
|
||||
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(regs->fp->prev() == NULL);
|
||||
|
@ -2078,8 +2068,6 @@ JSContext::saveActiveSegment()
|
|||
{
|
||||
JS_ASSERT(hasActiveSegment());
|
||||
currentSegment->save(regs);
|
||||
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
setCurrentRegs(NULL);
|
||||
}
|
||||
|
||||
|
@ -2089,9 +2077,6 @@ JSContext::restoreSegment()
|
|||
js::StackSegment *ccs = currentSegment;
|
||||
setCurrentRegs(ccs->getSuspendedRegs());
|
||||
ccs->restore();
|
||||
#ifdef DEBUG
|
||||
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
|
||||
JSGenerator *
|
||||
|
@ -2213,7 +2198,7 @@ JSContext::updateJITEnabled()
|
|||
#endif
|
||||
#ifdef JS_METHODJIT
|
||||
methodJitEnabled = (options & JSOPTION_METHODJIT)
|
||||
# ifdef JS_CPU_X86
|
||||
# if defined JS_CPU_X86 || defined JS_CPU_X64
|
||||
&& JSC::MacroAssemblerX86Common::getSSEState() >=
|
||||
JSC::MacroAssemblerX86Common::HasSSE2
|
||||
# endif
|
||||
|
|
|
@ -883,6 +883,7 @@ JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
|||
*/
|
||||
class FrameRegsIter
|
||||
{
|
||||
JSContext *cx;
|
||||
StackSegment *curseg;
|
||||
JSStackFrame *curfp;
|
||||
Value *cursp;
|
||||
|
@ -1477,6 +1478,9 @@ struct JSRuntime {
|
|||
*/
|
||||
JSSecurityCallbacks *securityCallbacks;
|
||||
|
||||
/* Structured data callbacks are runtime-wide. */
|
||||
const JSStructuredCloneCallbacks *structuredCloneCallbacks;
|
||||
|
||||
/*
|
||||
* Shared scope property tree, and arena-pool for allocating its nodes.
|
||||
* This really should be free of all locking overhead and allocated in
|
||||
|
@ -2090,6 +2094,9 @@ struct JSContext
|
|||
/* Undoes calls to suspendActiveSegment. */
|
||||
void restoreSegment();
|
||||
|
||||
/* Get the frame whose prev() is fp, which may be in any segment. */
|
||||
inline JSStackFrame *computeNextFrame(JSStackFrame *fp);
|
||||
|
||||
/*
|
||||
* Perform a linear search of all frames in all segments in the given context
|
||||
* for the given frame, returning the segment, if found, and null otherwise.
|
||||
|
|
|
@ -71,6 +71,21 @@ JSContext::ensureGeneratorStackSpace()
|
|||
return ok;
|
||||
}
|
||||
|
||||
JSStackFrame *
|
||||
JSContext::computeNextFrame(JSStackFrame *fp)
|
||||
{
|
||||
JSStackFrame *next = NULL;
|
||||
for (js::StackSegment *ss = currentSegment; ; ss = ss->getPreviousInContext()) {
|
||||
JSStackFrame *end = ss->getInitialFrame()->prev();
|
||||
for (JSStackFrame *f = ss->getCurrentFrame(); f != end; next = f, f = f->prev()) {
|
||||
if (f == fp)
|
||||
return next;
|
||||
}
|
||||
if (end != ss->getPreviousInContext()->getCurrentFrame())
|
||||
next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs *
|
||||
|
@ -309,16 +324,10 @@ StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
|
|||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
||||
|
||||
JSStackFrame *fp = fg->regs_.fp;
|
||||
JSStackFrame *prev = cx->maybefp();
|
||||
fp->prev_ = prev;
|
||||
fp->setPrev(cx->regs);
|
||||
if (JS_UNLIKELY(!currentSegment->inContext())) {
|
||||
cx->pushSegmentAndFrame(currentSegment, fg->regs_);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
JS_ASSERT(prev->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
#endif
|
||||
prev->savedpc_ = cx->regs->pc;
|
||||
fg->prevRegs_ = cx->regs;
|
||||
cx->setCurrentRegs(&fg->regs_);
|
||||
}
|
||||
|
@ -339,10 +348,8 @@ StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
|
|||
} else {
|
||||
JS_ASSERT(&fg.regs_ == cx->regs);
|
||||
JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
|
||||
JS_ASSERT(fp->prevpc() == fg.prevRegs_->pc);
|
||||
cx->setCurrentRegs(fg.prevRegs_);
|
||||
#ifdef DEBUG
|
||||
cx->fp()->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,11 +391,8 @@ StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
|
|||
JS_ASSERT(isCurrentAndActive(cx));
|
||||
JS_ASSERT(cx->regs == regs && script == fp->script());
|
||||
|
||||
regs->fp->savedpc_ = regs->pc;
|
||||
fp->prev_ = regs->fp;
|
||||
#ifdef DEBUG
|
||||
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
fp->setPrev(regs);
|
||||
|
||||
regs->fp = fp;
|
||||
regs->pc = script->code;
|
||||
regs->sp = fp->slots() + script->nfixed;
|
||||
|
@ -400,17 +404,13 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp)
|
|||
JS_ASSERT(isCurrentAndActive(cx));
|
||||
JS_ASSERT(cx->hasActiveSegment());
|
||||
JS_ASSERT(cx->regs->fp->prev_ == prev);
|
||||
JS_ASSERT(cx->regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||
JS_ASSERT(!cx->regs->fp->hasImacropc());
|
||||
JS_ASSERT(prev->base() <= newsp && newsp <= cx->regs->fp->formalArgsEnd());
|
||||
|
||||
JSFrameRegs *regs = cx->regs;
|
||||
regs->pc = prev->pc(cx, regs->fp);
|
||||
regs->fp = prev;
|
||||
regs->pc = prev->savedpc_;
|
||||
regs->sp = newsp;
|
||||
#ifdef DEBUG
|
||||
prev->savedpc_ = JSStackFrame::sInvalidpc;
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE Value *
|
||||
|
@ -442,6 +442,7 @@ StackSpace::getStackLimit(JSContext *cx)
|
|||
|
||||
JS_REQUIRES_STACK inline
|
||||
FrameRegsIter::FrameRegsIter(JSContext *cx)
|
||||
: cx(cx)
|
||||
{
|
||||
curseg = cx->getCurrentSegment();
|
||||
if (JS_UNLIKELY(!curseg || !curseg->isActive())) {
|
||||
|
@ -463,7 +464,7 @@ FrameRegsIter::operator++()
|
|||
if (!prev)
|
||||
return *this;
|
||||
|
||||
curpc = prev->savedpc_;
|
||||
curpc = curfp->pc(cx, fp);
|
||||
|
||||
if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
|
||||
incSlow(fp, prev);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче