Merge mozilla-central into asynchronous plugins branch.

This commit is contained in:
Benjamin Smedberg 2010-10-01 13:54:43 -04:00
Родитель e7d497dbc0 ae7f778e4a
Коммит 36ae808503
264 изменённых файлов: 14263 добавлений и 7272 удалений

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

@ -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*)&currentFramebuffer);
// 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

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

@ -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;

815
js/src/jsclone.cpp Normal file
Просмотреть файл

@ -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;
}

174
js/src/jsclone.h Normal file
Просмотреть файл

@ -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 &in;
// 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);

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