This commit is contained in:
Richard Newman 2011-12-06 00:27:07 -08:00
Родитель c2d2bf26e5 5987d6fd23
Коммит 95077b288f
205 изменённых файлов: 9370 добавлений и 3428 удалений

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

@ -787,10 +787,15 @@ interface nsIAccessibleRole : nsISupports
*/
const unsigned long ROLE_NOTE = 123;
/**
* A figure. Used for things like HTML5 figure element.
*/
const unsigned long ROLE_FIGURE = 124;
/**
* It's not role actually. This constant is important to help ensure
* nsRoleMap's are synchronized.
*/
const unsigned long ROLE_LAST_ENTRY = 124;
const unsigned long ROLE_LAST_ENTRY = 125;
};

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

@ -169,6 +169,7 @@ static const PRUint32 atkRoleMap[] = {
ATK_ROLE_TABLE_CELL, // nsIAccessibleRole::ROLE_GRID_CELL 121
ATK_ROLE_PANEL, // nsIAccessibleRole::ROLE_EMBEDDED_OBJECT 122
ATK_ROLE_SECTION, // nsIAccessibleRole::ROLE_NOTE 123
ATK_ROLE_PANEL, // nsIAccessibleRole::ROLE_FIGURE 124
kROLE_ATK_LAST_ENTRY // nsIAccessibleRole::ROLE_LAST_ENTRY
};

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

@ -1605,7 +1605,20 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
nsIWeakReference* aWeakShell)
{
// This method assumes we're in an HTML namespace.
nsIAtom *tag = aContent->Tag();
nsIAtom* tag = aContent->Tag();
if (tag == nsGkAtoms::figcaption) {
nsAccessible* accessible =
new nsHTMLFigcaptionAccessible(aContent, aWeakShell);
NS_IF_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::figure) {
nsAccessible* accessible = new nsHTMLFigureAccessible(aContent, aWeakShell);
NS_IF_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::legend) {
nsAccessible* accessible = new nsHTMLLegendAccessible(aContent, aWeakShell);
NS_IF_ADDREF(accessible);

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

@ -424,7 +424,8 @@ static const char kRoleNames[][20] = {
"flat equation", //ROLE_FLAT_EQUATION
"gridcell", //ROLE_GRID_CELL
"embedded object", //ROLE_EMBEDDED_OBJECT
"note" //ROLE_NOTE
"note", //ROLE_NOTE
"figure" //ROLE_FIGURE
};
/**

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

@ -793,3 +793,106 @@ nsHTMLLegendAccessible::NativeRole()
{
return nsIAccessibleRole::ROLE_LABEL;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLFigureAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLFigureAccessible::
nsHTMLFigureAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
nsHyperTextAccessibleWrap(aContent, aShell)
{
}
nsresult
nsHTMLFigureAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes)
{
nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes);
NS_ENSURE_SUCCESS(rv, rv);
// Expose figure xml-role.
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
NS_LITERAL_STRING("figure"));
return NS_OK;
}
PRUint32
nsHTMLFigureAccessible::NativeRole()
{
return nsIAccessibleRole::ROLE_FIGURE;
}
nsresult
nsHTMLFigureAccessible::GetNameInternal(nsAString& aName)
{
nsresult rv = nsHyperTextAccessibleWrap::GetNameInternal(aName);
NS_ENSURE_SUCCESS(rv, rv);
if (!aName.IsEmpty())
return NS_OK;
nsIContent* captionContent = Caption();
if (captionContent) {
return nsTextEquivUtils::
AppendTextEquivFromContent(this, captionContent, &aName);
}
return NS_OK;
}
Relation
nsHTMLFigureAccessible::RelationByType(PRUint32 aType)
{
Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
rel.AppendTarget(Caption());
return rel;
}
nsIContent*
nsHTMLFigureAccessible::Caption() const
{
for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
childContent = childContent->GetNextSibling()) {
if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
mContent->GetNameSpaceID())) {
return childContent;
}
}
return nsnull;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLFigcaptionAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLFigcaptionAccessible::
nsHTMLFigcaptionAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
nsHyperTextAccessibleWrap(aContent, aShell)
{
}
PRUint32
nsHTMLFigcaptionAccessible::NativeRole()
{
return nsIAccessibleRole::ROLE_CAPTION;
}
Relation
nsHTMLFigcaptionAccessible::RelationByType(PRUint32 aType)
{
Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
return rel;
nsAccessible* figure = Parent();
if (figure &&
figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
mContent->GetNameSpaceID())) {
rel.AppendTarget(figure);
}
return rel;
}

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

@ -228,4 +228,36 @@ public:
virtual Relation RelationByType(PRUint32 aType);
};
#endif
/**
* Accessible for HTML5 figure element.
*/
class nsHTMLFigureAccessible : public nsHyperTextAccessibleWrap
{
public:
nsHTMLFigureAccessible(nsIContent* aContent, nsIWeakReference* aShell);
// nsAccessible
virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes);
virtual nsresult GetNameInternal(nsAString& aName);
virtual PRUint32 NativeRole();
virtual Relation RelationByType(PRUint32 aType);
protected:
nsIContent* Caption() const;
};
/**
* Accessible for HTML5 figcaption element.
*/
class nsHTMLFigcaptionAccessible : public nsHyperTextAccessibleWrap
{
public:
nsHTMLFigcaptionAccessible(nsIContent* aContent, nsIWeakReference* aShell);
// nsAccessible
virtual PRUint32 NativeRole();
virtual Relation RelationByType(PRUint32 aType);
};
#endif

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

@ -166,5 +166,6 @@ static const NSString* AXRoles [] = {
NSAccessibilityGroupRole, // ROLE_GRID_CELL
NSAccessibilityGroupRole, // ROLE_EMBEDDED_OBJECT
NSAccessibilityGroupRole, // ROLE_NOTE
NSAccessibilityGroupRole, // ROLE_FIGURE
@"ROLE_LAST_ENTRY" // ROLE_LAST_ENTRY. bogus role that will never be shown (just marks the end of this array)!
};

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

@ -446,6 +446,9 @@ static const WindowsRoleMapItem gWindowsRoleMap[] = {
// nsIAccessibleRole::ROLE_NOTE
{ USE_ROLE_STRING, IA2_ROLE_NOTE },
// nsIAccessibleRole::ROLE_FIGURE
{ ROLE_SYSTEM_GROUPING, ROLE_SYSTEM_GROUPING },
// nsIAccessibleRole::ROLE_LAST_ENTRY
{ ROLE_WINDOWS_LAST_ENTRY, ROLE_WINDOWS_LAST_ENTRY }
};

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

@ -46,6 +46,7 @@ DIRS = \
actions \
attributes \
editabletext \
elm \
events \
focus \
hyperlink \
@ -94,10 +95,6 @@ _TEST_FILES =\
test_childAtPoint.html \
test_childAtPoint.xul \
test_descr.html \
test_elm_landmarks.html \
test_elm_listbox.xul \
test_elm_nsApplicationAcc.html \
test_elm_plugin.html \
test_nsIAccessibleDocument.html \
test_nsIAccessibleImage.html \
test_nsIAccessNode_utils.html \

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

@ -0,0 +1,57 @@
#
# ***** 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.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Alexander Surkov <surkov.alexander@gmail.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either of 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 *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible/elm
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_figure.html \
test_landmarks.html \
test_listbox.xul \
test_nsApplicationAcc.html \
test_plugin.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)

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

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML5 figure/figcaption tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../attributes.js"></script>
<script type="application/javascript"
src="../relations.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript">
function doTest()
{
testRole("figure", ROLE_FIGURE);
testRole("figcaption", ROLE_CAPTION);
todo(false, "figure name gets extra whitespace in the end!");
testName("figure", "figure caption ");
testName("figcaption", null);
testRelation("figure", RELATION_LABELLED_BY, "figcaption");
testRelation("figcaption", RELATION_LABEL_FOR, "figure");
testAttrs("figure", {"xml-roles" : "figure"}, true);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Implement figure and figcaption accessibility"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=658272">
Mozilla Bug 658272
</a><br/>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<figure id="figure">
<figcaption id="figcaption">figure caption</figcaption>
</figure>
</body>
</html>

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

@ -9,11 +9,11 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
src="../common.js"></script>
<script type="application/javascript"
src="role.js"></script>
src="../role.js"></script>
<script type="application/javascript"
src="attributes.js"></script>
src="../attributes.js"></script>
<script type="application/javascript">

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

@ -10,9 +10,9 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="common.js"></script>
src="../common.js"></script>
<script type="application/javascript"
src="role.js"></script>
src="../role.js"></script>
<script type="application/javascript">
<![CDATA[

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

@ -8,9 +8,9 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
src="../common.js"></script>
<script type="application/javascript"
src="role.js"></script>
src="../role.js"></script>
<script type="application/javascript">
function doTest()

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

@ -9,11 +9,11 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
src="../common.js"></script>
<script type="application/javascript"
src="role.js"></script>
src="../role.js"></script>
<script type="application/javascript"
src="states.js"></script>
src="../states.js"></script>
<script type="application/javascript">

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

@ -20,6 +20,7 @@ const ROLE_DIALOG = nsIAccessibleRole.ROLE_DIALOG;
const ROLE_DOCUMENT = nsIAccessibleRole.ROLE_DOCUMENT;
const ROLE_EMBEDDED_OBJECT = nsIAccessibleRole.ROLE_EMBEDDED_OBJECT;
const ROLE_ENTRY = nsIAccessibleRole.ROLE_ENTRY;
const ROLE_FIGURE = nsIAccessibleRole.ROLE_FIGURE;
const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;

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

@ -209,18 +209,20 @@ var gLanguagesDialog = {
if (arrayOfPrefs[i] == selectedID)
return;
}
this._selectedItemID = selectedID;
if (preference.value == "")
preference.value = selectedID;
else
preference.value += "," + selectedID;
else {
arrayOfPrefs.unshift(selectedID);
preference.value = arrayOfPrefs.join(",");
}
this._acceptLanguages[selectedID] = true;
this._availableLanguages.selectedItem = null;
// Reuild the available list with the added item removed...
// Rebuild the available list with the added item removed...
this._buildAvailableLanguageList();
this._availableLanguages.setAttribute("label", this._availableLanguages.getAttribute("label2"));

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

@ -136,6 +136,10 @@
@BINPATH@/components/dom.xpt
@BINPATH@/components/dom_apps.xpt
@BINPATH@/components/dom_base.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_telephony.xpt
@BINPATH@/components/dom_telephony_worker.xpt
#endif
@BINPATH@/components/dom_battery.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_core.xpt
@ -358,6 +362,12 @@
@BINPATH@/components/contentSecurityPolicy.js
@BINPATH@/components/contentAreaDropListener.manifest
@BINPATH@/components/contentAreaDropListener.js
#ifdef MOZ_B2G_RIL
@BINPATH@/components/nsTelephonyWorker.manifest
@BINPATH@/components/nsTelephonyWorker.js
@BINPATH@/components/Telephony.manifest
@BINPATH@/components/Telephony.js
#endif
@BINPATH@/components/BrowserProfileMigrators.manifest
@BINPATH@/components/ChromeProfileMigrator.js
#ifdef XP_MACOSX

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

@ -68,6 +68,10 @@ components/nsUrlClassifierTable.js
components/nsXmlRpcClient.js
components/pluginGlue.js
components/sidebar.xpt
#ifdef MOZ_B2G_RIL
components/dom_telephony.xpt
components/dom_telephony_worker.xpt
#endif
components/WeaveCrypto.js
components/WeaveCrypto.manifest
components/xmlextras.xpt
@ -230,6 +234,7 @@ greprefs/xpinstall.js
install.rdf
modules/ISO8601DateUtils.jsm
modules/JSON.jsm
modules/SpatialNavigation.js
modules/utils.js
mozilla-runtime@BIN_SUFFIX@
old-homepage-default.properties
@ -912,6 +917,12 @@ xpicleanup@BIN_SUFFIX@
components/PlacesProtocolHandler.js
components/storage-Legacy.js
components/storage-mozStorage.js
#ifdef MOZ_B2G_RIL
components/nsTelephonyWorker.manifest
components/nsTelephonyWorker.js
components/Telephony.manifest
components/Telephony.js
#endif
components/txEXSLTRegExFunctions.js
components/Weave.js
components/WebContentConverter.js
@ -1129,6 +1140,10 @@ xpicleanup@BIN_SUFFIX@
components/docshell.xpt
components/dom.xpt
components/dom_base.xpt
#ifdef MOZ_B2G_RIL
components/dom_telephony.xpt
components/dom_telephony_worker.xpt
#endif
components/dom_canvas.xpt
components/dom_core.xpt
components/dom_css.xpt
@ -1298,6 +1313,7 @@ xpicleanup@BIN_SUFFIX@
components/libimgicon.so
dictionaries/PL.aff
dictionaries/PL.dic
icons/document.png
icons/mozicon16.xpm
icons/mozicon50.xpm
plugins/libnullplugin.so

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

@ -3,6 +3,7 @@ from devicemanager import DeviceManager, DMError
import re
import os
import sys
import tempfile
class DeviceManagerADB(DeviceManager):
@ -13,6 +14,7 @@ class DeviceManagerADB(DeviceManager):
self.retries = 0
self._sock = None
self.useRunAs = False
self.useZip = False
self.packageName = None
if packageName == None:
if os.getenv('USER'):
@ -30,6 +32,10 @@ class DeviceManagerADB(DeviceManager):
except:
self.useRunAs = False
self.packageName = None
try:
self.verifyZip()
except:
self.useZip = False
try:
# a test to see if we have root privs
files = self.listFiles("/data/data")
@ -103,31 +109,41 @@ class DeviceManagerADB(DeviceManager):
def pushDir(self, localDir, remoteDir):
# adb "push" accepts a directory as an argument, but if the directory
# contains symbolic links, the links are pushed, rather than the linked
# files; we push file-by-file to get around this limitation
# files; we either zip/unzip or push file-by-file to get around this
# limitation
try:
if (not self.dirExists(remoteDir)):
self.mkDirs(remoteDir+"/x")
for root, dirs, files in os.walk(localDir, followlinks='true'):
relRoot = os.path.relpath(root, localDir)
for file in files:
localFile = os.path.join(root, file)
remoteFile = remoteDir + "/"
if (relRoot!="."):
remoteFile = remoteFile + relRoot + "/"
remoteFile = remoteFile + file
self.pushFile(localFile, remoteFile)
for dir in dirs:
targetDir = remoteDir + "/"
if (relRoot!="."):
targetDir = targetDir + relRoot + "/"
targetDir = targetDir + dir
if (not self.dirExists(targetDir)):
self.mkDir(targetDir)
if (self.useZip):
localZip = tempfile.mktemp()+".zip"
remoteZip = remoteDir + "/adbdmtmp.zip"
subprocess.check_output(["zip", "-r", localZip, '.'], cwd=localDir)
self.pushFile(localZip, remoteZip)
os.remove(localZip)
self.checkCmdAs(["shell", "unzip", "-o", remoteZip, "-d", remoteDir])
self.checkCmdAs(["shell", "rm", remoteZip])
else:
if (not self.dirExists(remoteDir)):
self.mkDirs(remoteDir+"/x")
for root, dirs, files in os.walk(localDir, followlinks='true'):
relRoot = os.path.relpath(root, localDir)
for file in files:
localFile = os.path.join(root, file)
remoteFile = remoteDir + "/"
if (relRoot!="."):
remoteFile = remoteFile + relRoot + "/"
remoteFile = remoteFile + file
self.pushFile(localFile, remoteFile)
for dir in dirs:
targetDir = remoteDir + "/"
if (relRoot!="."):
targetDir = targetDir + relRoot + "/"
targetDir = targetDir + dir
if (not self.dirExists(targetDir)):
self.mkDir(targetDir)
self.checkCmdAs(["shell", "chmod", "777", remoteDir])
return True
return remoteDir
except:
print "pushing " + localDir + " to " + remoteDir + " failed"
return False
return None
# external function
# returns:
@ -241,11 +257,25 @@ class DeviceManagerADB(DeviceManager):
acmd = ["shell", "am","start"]
cmd = ' '.join(cmd).strip()
i = cmd.find(" ")
# SUT identifies the URL by looking for :\\ -- another strategy to consider
re_url = re.compile('^[http|file|chrome|about].*')
last = cmd.rfind(" ")
uri = ""
args = ""
if re_url.match(cmd[last:].strip()):
args = cmd[i:last].strip()
uri = cmd[last:].strip()
else:
args = cmd[i:].strip()
acmd.append("-n")
acmd.append(cmd[0:i] + "/.App")
acmd.append("--es")
acmd.append("args")
acmd.append(cmd[i:])
if args != "":
acmd.append("args")
acmd.append(args)
if uri != "":
acmd.append("-d")
acmd.append(''.join(['\'',uri, '\'']));
print acmd
self.checkCmd(acmd)
return outputFile;
@ -578,3 +608,25 @@ class DeviceManagerADB(DeviceManager):
self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"])
def isUnzipAvailable(self):
data = self.runCmd(["shell", "unzip"]).stdout.read()
if (re.search('Usage', data)):
return True
else:
return False
def isLocalZipAvailable(self):
try:
subprocess.check_call(["zip", "-?"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except:
return False
return True
def verifyZip(self):
# If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
# can use these to push just one file per directory -- a significant
# optimization for large directories.
self.useZip = False
if (self.isUnzipAvailable() and self.isLocalZipAvailable()):
print "will use zip to push directories"
self.useZip = True

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

@ -129,7 +129,6 @@ MOZ_LIBSTDCXX_TARGET_VERSION=@MOZ_LIBSTDCXX_TARGET_VERSION@
MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
INCREMENTAL_LINKER = @INCREMENTAL_LINKER@
MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@
MOZ_MAIL_NEWS = @MOZ_MAIL_NEWS@
ENABLE_TESTS = @ENABLE_TESTS@
IBMBIDI = @IBMBIDI@
MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
@ -289,6 +288,8 @@ MOZ_GIO_LIBS = @MOZ_GIO_LIBS@
MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
MOZ_B2G_RIL = @MOZ_B2G_RIL@
BUILD_CTYPES = @BUILD_CTYPES@
COMPILE_ENVIRONMENT = @COMPILE_ENVIRONMENT@

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

@ -4981,6 +4981,7 @@ cairo-gonk)
TK_LIBS='$(MOZ_CAIRO_LIBS)'
MOZ_WEBGL=1
MOZ_PDF_PRINTING=1
MOZ_B2G_RIL=1
;;
esac
@ -7573,6 +7574,18 @@ MOZ_ARG_ENABLE_BOOL(quantify,
MOZ_QUANTIFY=1,
MOZ_QUANTIFY= )
dnl ========================================================
dnl = Enable Radio Interface for B2G (Gonk usually)
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(b2g-ril,
[ --enable-b2g-ril Set compile flags necessary for testing B2G Radio Interface Layer via network sockets ],
MOZ_B2G_RIL=1,
MOZ_B2G_RIL= )
if test -n "$MOZ_B2G_RIL"; then
AC_DEFINE(MOZ_B2G_RIL)
fi
AC_SUBST(MOZ_B2G_RIL)
dnl ========================================================
dnl = Support for demangling undefined symbols
dnl ========================================================

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

@ -0,0 +1,7 @@
onmessage = function(event) {
var blob = event.data;
blob.mozSlice(1, 5);
postMessage("done");
}

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

@ -0,0 +1,16 @@
<html class="reftest-wait">
<script type="text/javascript">
var worker = new Worker("700512-worker.js");
var bb = new MozBlobBuilder();
bb.append("foo");
bb.append("bar");
worker.onmessage = function() {
document.documentElement.removeAttribute("class");
}
worker.postMessage(bb.getBlob());
</script>
</html>

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

@ -100,4 +100,5 @@ load 693212.xhtml
load 698974-1.html
load 700090-1.html
load 700090-2.html
load 700512.html
load xhr_html_nullresponse.html

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

@ -141,7 +141,7 @@ interface nsIContentViewManager : nsISupports
readonly attribute nsIContentView rootContentView;
};
[scriptable, uuid(12905a29-4246-475a-81d4-fc389197df02)]
[scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)]
interface nsIFrameLoader : nsISupports
{
/**
@ -258,6 +258,13 @@ interface nsIFrameLoader : nsISupports
const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
attribute unsigned long eventMode;
/**
* If false, then the subdocument is not clipped to its CSS viewport, and the
* subdocument's viewport scrollbar(s) are not rendered.
* Defaults to true.
*/
attribute boolean clipSubdocument;
};
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);

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

@ -143,14 +143,12 @@ public:
nsRefPtr<nsIDocShell> mDocShell;
};
static void InvalidateFrame(nsIFrame* aFrame)
static void InvalidateFrame(nsIFrame* aFrame, PRUint32 aFlags)
{
if (!aFrame)
return;
nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process
// <browser>. This is just a transform of the layer subtree in
// both.
aFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
aFrame->InvalidateWithFlags(rect, aFlags);
}
NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
@ -189,8 +187,11 @@ nsContentView::Update(const ViewConfig& aConfig)
// XXX could be clever here and compute a smaller invalidation
// rect
nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent();
InvalidateFrame(frame);
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process
// <browser>. This is just a transform of the layer subtree in
// both.
InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
return NS_OK;
}
@ -328,6 +329,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mDelayRemoteDialogs(false)
, mRemoteBrowserShown(false)
, mRemoteFrame(false)
, mClipSubdocument(true)
, mCurrentRemoteFrame(nsnull)
, mRemoteBrowser(nsnull)
, mRenderMode(RENDER_MODE_DEFAULT)
@ -1693,7 +1695,11 @@ nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
}
mRenderMode = aRenderMode;
InvalidateFrame(GetPrimaryFrameOfOwningContent());
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process
// <browser>. This is just a transform of the layer subtree in
// both.
InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
return NS_OK;
}
@ -1711,6 +1717,38 @@ nsFrameLoader::SetEventMode(PRUint32 aEventMode)
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::GetClipSubdocument(bool* aResult)
{
*aResult = mClipSubdocument;
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::SetClipSubdocument(bool aClip)
{
mClipSubdocument = aClip;
nsIFrame* frame = GetPrimaryFrameOfOwningContent();
if (frame) {
InvalidateFrame(frame, 0);
frame->PresContext()->PresShell()->
FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
if (subdocFrame) {
nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
if (subdocRootFrame) {
nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
GetRootScrollFrame();
if (subdocRootScrollFrame) {
frame->PresContext()->PresShell()->
FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
}
}
}
}
return NS_OK;
}
nsIntSize
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
{

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

@ -287,6 +287,8 @@ public:
mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
void SetOwnerContent(mozilla::dom::Element* aContent);
bool ShouldClipSubdocument() { return mClipSubdocument; }
private:
bool ShouldUseRemoteProcess();
@ -338,7 +340,9 @@ private:
bool mDelayRemoteDialogs : 1;
bool mRemoteBrowserShown : 1;
bool mRemoteFrame;
bool mRemoteFrame : 1;
bool mClipSubdocument : 1;
// XXX leaking
nsCOMPtr<nsIObserver> mChildHost;
RenderFrameParent* mCurrentRemoteFrame;

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

@ -236,13 +236,6 @@ WebGLContext::WebGLContext()
mShaderValidation = true;
mMapBuffers.Init();
mMapTextures.Init();
mMapPrograms.Init();
mMapShaders.Init();
mMapFramebuffers.Init();
mMapRenderbuffers.Init();
mBlackTexturesAreInitialized = false;
mFakeBlackStatus = DoNotNeedFakeBlack;
@ -314,72 +307,6 @@ WebGLContext::~WebGLContext()
mContextRestorer = nsnull;
}
static PLDHashOperator
DeleteTextureFunction(const PRUint32& aKey, WebGLTexture *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Texture is still in mMapTextures, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteTextures(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteBufferFunction(const PRUint32& aKey, WebGLBuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Buffer is still in mMapBuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteBuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteFramebufferFunction(const PRUint32& aKey, WebGLFramebuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Framebuffer is still in mMapFramebuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteFramebuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteRenderbufferFunction(const PRUint32& aKey, WebGLRenderbuffer *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Renderbuffer is still in mMapRenderbuffers, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteRenderbuffers(1, &name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteProgramFunction(const PRUint32& aKey, WebGLProgram *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Program is still in mMapPrograms, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteProgram(name);
aValue->Delete();
return PL_DHASH_NEXT;
}
static PLDHashOperator
DeleteShaderFunction(const PRUint32& aKey, WebGLShader *aValue, void *aData)
{
gl::GLContext *gl = (gl::GLContext *) aData;
NS_ASSERTION(!aValue->Deleted(), "Shader is still in mMapShaders, but is deleted?");
GLuint name = aValue->GLName();
gl->fDeleteShader(name);
aValue->Delete();
return PL_DHASH_NEXT;
}
void
WebGLContext::DestroyResourcesAndContext()
{
@ -388,23 +315,30 @@ WebGLContext::DestroyResourcesAndContext()
gl->MakeCurrent();
mMapTextures.EnumerateRead(DeleteTextureFunction, gl);
mMapTextures.Clear();
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBoundArrayBuffer = nsnull;
mBoundElementArrayBuffer = nsnull;
mCurrentProgram = nsnull;
mBoundFramebuffer = nsnull;
mBoundRenderbuffer = nsnull;
mMapBuffers.EnumerateRead(DeleteBufferFunction, gl);
mMapBuffers.Clear();
mAttribBuffers.Clear();
mMapPrograms.EnumerateRead(DeleteProgramFunction, gl);
mMapPrograms.Clear();
mMapShaders.EnumerateRead(DeleteShaderFunction, gl);
mMapShaders.Clear();
mMapFramebuffers.EnumerateRead(DeleteFramebufferFunction, gl);
mMapFramebuffers.Clear();
mMapRenderbuffers.EnumerateRead(DeleteRenderbufferFunction, gl);
mMapRenderbuffers.Clear();
while (mTextures.Length())
mTextures.Last()->DeleteOnce();
while (mBuffers.Length())
mBuffers.Last()->DeleteOnce();
while (mRenderbuffers.Length())
mRenderbuffers.Last()->DeleteOnce();
while (mFramebuffers.Length())
mFramebuffers.Last()->DeleteOnce();
while (mShaders.Length())
mShaders.Last()->DeleteOnce();
while (mPrograms.Length())
mPrograms.Last()->DeleteOnce();
while (mUniformLocations.Length())
mUniformLocations.Last()->DeleteOnce();
if (mBlackTexturesAreInitialized) {
gl->fDeleteTextures(1, &mBlackTexture2D);
@ -1270,7 +1204,6 @@ NS_IMPL_RELEASE(WebGLBuffer)
DOMCI_DATA(WebGLBuffer, WebGLBuffer)
NS_INTERFACE_MAP_BEGIN(WebGLBuffer)
NS_INTERFACE_MAP_ENTRY(WebGLBuffer)
NS_INTERFACE_MAP_ENTRY(nsIWebGLBuffer)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLBuffer)
@ -1282,7 +1215,6 @@ NS_IMPL_RELEASE(WebGLTexture)
DOMCI_DATA(WebGLTexture, WebGLTexture)
NS_INTERFACE_MAP_BEGIN(WebGLTexture)
NS_INTERFACE_MAP_ENTRY(WebGLTexture)
NS_INTERFACE_MAP_ENTRY(nsIWebGLTexture)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLTexture)
@ -1294,7 +1226,6 @@ NS_IMPL_RELEASE(WebGLProgram)
DOMCI_DATA(WebGLProgram, WebGLProgram)
NS_INTERFACE_MAP_BEGIN(WebGLProgram)
NS_INTERFACE_MAP_ENTRY(WebGLProgram)
NS_INTERFACE_MAP_ENTRY(nsIWebGLProgram)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLProgram)
@ -1306,7 +1237,6 @@ NS_IMPL_RELEASE(WebGLShader)
DOMCI_DATA(WebGLShader, WebGLShader)
NS_INTERFACE_MAP_BEGIN(WebGLShader)
NS_INTERFACE_MAP_ENTRY(WebGLShader)
NS_INTERFACE_MAP_ENTRY(nsIWebGLShader)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLShader)
@ -1318,7 +1248,6 @@ NS_IMPL_RELEASE(WebGLFramebuffer)
DOMCI_DATA(WebGLFramebuffer, WebGLFramebuffer)
NS_INTERFACE_MAP_BEGIN(WebGLFramebuffer)
NS_INTERFACE_MAP_ENTRY(WebGLFramebuffer)
NS_INTERFACE_MAP_ENTRY(nsIWebGLFramebuffer)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLFramebuffer)
@ -1330,7 +1259,6 @@ NS_IMPL_RELEASE(WebGLRenderbuffer)
DOMCI_DATA(WebGLRenderbuffer, WebGLRenderbuffer)
NS_INTERFACE_MAP_BEGIN(WebGLRenderbuffer)
NS_INTERFACE_MAP_ENTRY(WebGLRenderbuffer)
NS_INTERFACE_MAP_ENTRY(nsIWebGLRenderbuffer)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLRenderbuffer)
@ -1342,7 +1270,6 @@ NS_IMPL_RELEASE(WebGLUniformLocation)
DOMCI_DATA(WebGLUniformLocation, WebGLUniformLocation)
NS_INTERFACE_MAP_BEGIN(WebGLUniformLocation)
NS_INTERFACE_MAP_ENTRY(WebGLUniformLocation)
NS_INTERFACE_MAP_ENTRY(nsIWebGLUniformLocation)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLUniformLocation)
@ -1354,7 +1281,6 @@ NS_IMPL_RELEASE(WebGLActiveInfo)
DOMCI_DATA(WebGLActiveInfo, WebGLActiveInfo)
NS_INTERFACE_MAP_BEGIN(WebGLActiveInfo)
NS_INTERFACE_MAP_ENTRY(WebGLActiveInfo)
NS_INTERFACE_MAP_ENTRY(nsIWebGLActiveInfo)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLActiveInfo)
@ -1379,7 +1305,6 @@ NS_IMPL_RELEASE(WebGLExtension)
DOMCI_DATA(WebGLExtension, WebGLExtension)
NS_INTERFACE_MAP_BEGIN(WebGLExtension)
NS_INTERFACE_MAP_ENTRY(WebGLExtension)
NS_INTERFACE_MAP_ENTRY(nsIWebGLExtension)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtension)
@ -1391,8 +1316,6 @@ NS_IMPL_RELEASE(WebGLExtensionStandardDerivatives)
DOMCI_DATA(WebGLExtensionStandardDerivatives, WebGLExtensionStandardDerivatives)
NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives)
//NS_INTERFACE_MAP_ENTRY(WebGLExtensionStandardDerivatives)
//NS_INTERFACE_MAP_ENTRY(WebGLExtension)
NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -121,22 +121,6 @@ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
}
already_AddRefed<WebGLUniformLocation>
WebGLProgram::GetUniformLocationObject(GLint glLocation)
{
WebGLUniformLocation *existingLocationObject;
if (mMapUniformLocations.Get(glLocation, &existingLocationObject)) {
return existingLocationObject;
}
if (glLocation < 0) {
return nsnull;
}
nsRefPtr<WebGLUniformLocation> loc = new WebGLUniformLocation(mContext, this, glLocation);
mMapUniformLocations.Put(glLocation, loc);
return loc.forget();
}
//
// WebGL API
@ -150,7 +134,7 @@ WebGLContext::ActiveTexture(WebGLenum texture)
if (mContextLost)
return NS_OK;
if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0+mBound2DTextures.Length())
if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0 + mBound2DTextures.Length())
return ErrorInvalidEnum("ActiveTexture: texture unit %d out of range (0..%d)",
texture, mBound2DTextures.Length()-1);
@ -186,10 +170,6 @@ WebGLContext::AttachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj)
if (!program->AttachShader(shader))
return ErrorInvalidOperation("AttachShader: shader is already attached");
MakeContextCurrent();
gl->fAttachShader(progname, shadername);
return NS_OK;
}
@ -1087,13 +1067,8 @@ WebGLContext::CreateProgram(nsIWebGLProgram **retval)
*retval = nsnull;
MakeContextCurrent();
WebGLuint name = gl->fCreateProgram();
WebGLProgram *prog = new WebGLProgram(this, name);
WebGLProgram *prog = new WebGLProgram(this);
NS_ADDREF(*retval = prog);
mMapPrograms.Put(name, prog);
return NS_OK;
}
@ -1112,13 +1087,8 @@ WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval)
return ErrorInvalidEnumInfo("createShader: type", type);
}
MakeContextCurrent();
WebGLuint name = gl->fCreateShader(type);
WebGLShader *shader = new WebGLShader(this, name, type);
WebGLShader *shader = new WebGLShader(this, type);
NS_ADDREF(*retval = shader);
mMapShaders.Put(name, shader);
return NS_OK;
}
@ -1152,11 +1122,17 @@ WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
if (mBoundArrayBuffer == buf)
BindBuffer(LOCAL_GL_ARRAY_BUFFER, nsnull);
if (mBoundElementArrayBuffer == buf)
BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nsnull);
gl->fDeleteBuffers(1, &bufname);
buf->Delete();
mMapBuffers.Remove(bufname);
for (int i = 0; i < mGLMaxVertexAttribs; i++) {
if (mAttribBuffers[i].buf == buf)
mAttribBuffers[i].buf = nsnull;
}
buf->RequestDelete();
return NS_OK;
}
@ -1167,8 +1143,8 @@ WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj)
if (mContextLost)
return NS_OK;
WebGLuint fbufname;
WebGLFramebuffer *fbuf;
WebGLuint fbufname;
bool isNull, isDeleted;
if (!GetConcreteObjectAndGLName("deleteFramebuffer", fbobj, &fbuf, &fbufname, &isNull, &isDeleted))
return NS_OK;
@ -1176,14 +1152,10 @@ WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
fbuf->RequestDelete();
gl->fDeleteFramebuffers(1, &fbufname);
fbuf->Delete();
mMapFramebuffers.Remove(fbufname);
if (mBoundFramebuffer && mBoundFramebuffer->GLName() == fbufname)
mBoundFramebuffer = NULL;
if (mBoundFramebuffer == fbuf)
BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nsnull);
return NS_OK;
}
@ -1194,8 +1166,8 @@ WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj)
if (mContextLost)
return NS_OK;
WebGLuint rbufname;
WebGLRenderbuffer *rbuf;
WebGLuint rbufname;
bool isNull, isDeleted;
if (!GetConcreteObjectAndGLName("deleteRenderbuffer", rbobj, &rbuf, &rbufname, &isNull, &isDeleted))
return NS_OK;
@ -1203,26 +1175,13 @@ WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
if (mBoundFramebuffer)
mBoundFramebuffer->DetachRenderbuffer(rbuf);
// XXX we need to track renderbuffer attachments; from glDeleteRenderbuffers man page:
if (mBoundRenderbuffer == rbuf)
BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nsnull);
/*
If a renderbuffer object that is currently bound is deleted, the binding reverts
to 0 (the absence of any renderbuffer object). Additionally, special care
must be taken when deleting a renderbuffer object if the image of the renderbuffer
is attached to a framebuffer object. In this case, if the deleted renderbuffer object is
attached to the currently bound framebuffer object, it is
automatically detached. However, attachments to any other framebuffer objects are the
responsibility of the application.
*/
gl->fDeleteRenderbuffers(1, &rbufname);
rbuf->Delete();
mMapRenderbuffers.Remove(rbufname);
if (mBoundRenderbuffer && mBoundRenderbuffer->GLName() == rbufname)
mBoundRenderbuffer = NULL;
rbuf->RequestDelete();
return NS_OK;
}
@ -1233,8 +1192,8 @@ WebGLContext::DeleteTexture(nsIWebGLTexture *tobj)
if (mContextLost)
return NS_OK;
WebGLuint texname;
WebGLTexture *tex;
WebGLuint texname;
bool isNull, isDeleted;
if (!GetConcreteObjectAndGLName("deleteTexture", tobj, &tex, &texname, &isNull, &isDeleted))
return NS_OK;
@ -1242,11 +1201,20 @@ WebGLContext::DeleteTexture(nsIWebGLTexture *tobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
if (mBoundFramebuffer)
mBoundFramebuffer->DetachTexture(tex);
gl->fDeleteTextures(1, &texname);
tex->Delete();
mMapTextures.Remove(texname);
for (int i = 0; i < mGLMaxTextureUnits; i++) {
if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
(tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
{
ActiveTexture(LOCAL_GL_TEXTURE0 + i);
BindTexture(tex->Target(), nsnull);
}
}
ActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
tex->RequestDelete();
return NS_OK;
}
@ -1266,12 +1234,7 @@ WebGLContext::DeleteProgram(nsIWebGLProgram *pobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
gl->fDeleteProgram(progname);
prog->DeleteWhenNotCurrent();
mMapPrograms.Remove(progname);
prog->RequestDelete();
return NS_OK;
}
@ -1291,11 +1254,7 @@ WebGLContext::DeleteShader(nsIWebGLShader *sobj)
if (isNull || isDeleted)
return NS_OK;
MakeContextCurrent();
gl->fDeleteShader(shadername);
shader->DeleteWhenNotAttached();
mMapShaders.Remove(shadername);
shader->RequestDelete();
return NS_OK;
}
@ -1319,12 +1278,6 @@ WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj)
if (!program->DetachShader(shader))
return ErrorInvalidOperation("DetachShader: shader is not attached");
MakeContextCurrent();
gl->fDetachShader(progname, shadername);
shader->DetachedFromProgram();
return NS_OK;
}
@ -2555,14 +2508,8 @@ WebGLContext::CreateBuffer(nsIWebGLBuffer **retval)
*retval = nsnull;
MakeContextCurrent();
WebGLuint name;
gl->fGenBuffers(1, &name);
WebGLBuffer *globj = new WebGLBuffer(this, name);
WebGLBuffer *globj = new WebGLBuffer(this);
NS_ADDREF(*retval = globj);
mMapBuffers.Put(name, globj);
return NS_OK;
}
@ -2577,12 +2524,8 @@ WebGLContext::CreateTexture(nsIWebGLTexture **retval)
MakeContextCurrent();
WebGLuint name;
gl->fGenTextures(1, &name);
WebGLTexture *globj = new WebGLTexture(this, name);
WebGLTexture *globj = new WebGLTexture(this);
NS_ADDREF(*retval = globj);
mMapTextures.Put(name, globj);
return NS_OK;
}
@ -2611,7 +2554,8 @@ WebGLContext::GetProgramParameter(nsIWebGLProgram *pobj, PRUint32 pname, nsIVari
WebGLuint progname;
bool isDeleted;
if (!GetGLName<WebGLProgram>("getProgramParameter: program", pobj, &progname, nsnull, &isDeleted))
WebGLProgram *prog;
if (!GetConcreteObjectAndGLName("getProgramParameter: program", pobj, &prog, &progname, nsnull, &isDeleted))
return NS_OK;
nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
@ -2634,6 +2578,8 @@ WebGLContext::GetProgramParameter(nsIWebGLProgram *pobj, PRUint32 pname, nsIVari
}
break;
case LOCAL_GL_DELETE_STATUS:
wrval->SetAsBool(prog->IsDeleteRequested());
break;
case LOCAL_GL_LINK_STATUS:
{
GLint i = 0;
@ -2992,9 +2938,10 @@ WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, n
GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
nsRefPtr<nsIWebGLUniformLocation> loc = prog->GetUniformLocationObject(intlocation);
*retval = loc.forget().get();
WebGLUniformLocation *loc = nsnull;
if (intlocation >= 0)
NS_ADDREF(loc = new WebGLUniformLocation(this, prog, intlocation));
*retval = loc;
return NS_OK;
}
@ -3123,15 +3070,9 @@ WebGLContext::IsBuffer(nsIWebGLBuffer *bobj, WebGLboolean *retval)
bool isDeleted;
WebGLuint buffername;
WebGLBuffer *buffer;
bool ok = GetConcreteObjectAndGLName("isBuffer", bobj, &buffer, &buffername, nsnull, &isDeleted) &&
!isDeleted &&
buffer->HasEverBeenBound();
if (ok) {
MakeContextCurrent();
ok = gl->fIsBuffer(buffername);
}
*retval = ok;
*retval = GetConcreteObjectAndGLName("isBuffer", bobj, &buffer, &buffername, nsnull, &isDeleted) &&
!isDeleted &&
buffer->HasEverBeenBound();
return NS_OK;
}
@ -3147,15 +3088,9 @@ WebGLContext::IsFramebuffer(nsIWebGLFramebuffer *fbobj, WebGLboolean *retval)
bool isDeleted;
WebGLuint fbname;
WebGLFramebuffer *fb;
bool ok = GetConcreteObjectAndGLName("isFramebuffer", fbobj, &fb, &fbname, nsnull, &isDeleted) &&
!isDeleted &&
fb->HasEverBeenBound();
if (ok) {
MakeContextCurrent();
ok = gl->fIsFramebuffer(fbname);
}
*retval = ok;
*retval = GetConcreteObjectAndGLName("isFramebuffer", fbobj, &fb, &fbname, nsnull, &isDeleted) &&
!isDeleted &&
fb->HasEverBeenBound();
return NS_OK;
}
@ -3170,10 +3105,8 @@ WebGLContext::IsProgram(nsIWebGLProgram *pobj, WebGLboolean *retval)
bool isDeleted;
WebGLProgram *prog = nsnull;
bool ok = GetConcreteObject("isProgram", pobj, &prog, nsnull, &isDeleted, false) &&
!isDeleted;
*retval = ok;
*retval = GetConcreteObject("isProgram", pobj, &prog, nsnull, &isDeleted, false) &&
!isDeleted;
return NS_OK;
}
@ -3189,15 +3122,9 @@ WebGLContext::IsRenderbuffer(nsIWebGLRenderbuffer *rbobj, WebGLboolean *retval)
bool isDeleted;
WebGLuint rbname;
WebGLRenderbuffer *rb;
bool ok = GetConcreteObjectAndGLName("isRenderBuffer", rbobj, &rb, &rbname, nsnull, &isDeleted) &&
!isDeleted &&
rb->HasEverBeenBound();
if (ok) {
MakeContextCurrent();
ok = gl->fIsRenderbuffer(rbname);
}
*retval = ok;
*retval = GetConcreteObjectAndGLName("isRenderBuffer", rbobj, &rb, &rbname, nsnull, &isDeleted) &&
!isDeleted &&
rb->HasEverBeenBound();
return NS_OK;
}
@ -3212,10 +3139,8 @@ WebGLContext::IsShader(nsIWebGLShader *sobj, WebGLboolean *retval)
bool isDeleted;
WebGLShader *shader = nsnull;
bool ok = GetConcreteObject("isShader", sobj, &shader, nsnull, &isDeleted, false) &&
!isDeleted;
*retval = ok;
*retval = GetConcreteObject("isShader", sobj, &shader, nsnull, &isDeleted, false) &&
!isDeleted;
return NS_OK;
}
@ -3231,15 +3156,9 @@ WebGLContext::IsTexture(nsIWebGLTexture *tobj, WebGLboolean *retval)
bool isDeleted;
WebGLuint texname;
WebGLTexture *tex;
bool ok = GetConcreteObjectAndGLName("isTexture", tobj, &tex, &texname, nsnull, &isDeleted) &&
!isDeleted &&
tex->HasEverBeenBound();
if (ok) {
MakeContextCurrent();
ok = gl->fIsTexture(texname);
}
*retval = ok;
*retval = GetConcreteObjectAndGLName("isTexture", tobj, &tex, &texname, nsnull, &isDeleted) &&
!isDeleted &&
tex->HasEverBeenBound();
return NS_OK;
}
@ -4336,12 +4255,8 @@ WebGLContext::UseProgram(nsIWebGLProgram *pobj)
gl->fUseProgram(progname);
WebGLProgram* previous = mCurrentProgram;
mCurrentProgram = prog;
if (previous)
previous->NoLongerCurrent();
return NS_OK;
}
@ -4376,14 +4291,8 @@ WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval)
*retval = 0;
MakeContextCurrent();
GLuint name;
gl->fGenFramebuffers(1, &name);
WebGLFramebuffer *globj = new WebGLFramebuffer(this, name);
WebGLFramebuffer *globj = new WebGLFramebuffer(this);
NS_ADDREF(*retval = globj);
mMapFramebuffers.Put(name, globj);
return NS_OK;
}
@ -4396,14 +4305,8 @@ WebGLContext::CreateRenderbuffer(nsIWebGLRenderbuffer **retval)
*retval = 0;
MakeContextCurrent();
GLuint name;
gl->fGenRenderbuffers(1, &name);
WebGLRenderbuffer *globj = new WebGLRenderbuffer(this, name);
WebGLRenderbuffer *globj = new WebGLRenderbuffer(this);
NS_ADDREF(*retval = globj);
mMapRenderbuffers.Put(name, globj);
return NS_OK;
}
@ -4566,6 +4469,8 @@ WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, nsIVaria
}
break;
case LOCAL_GL_DELETE_STATUS:
wrval->SetAsBool(shader->IsDeleteRequested());
break;
case LOCAL_GL_COMPILE_STATUS:
{
GLint i = 0;

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

@ -57,10 +57,10 @@ using namespace mozilla;
bool
WebGLProgram::UpdateInfo(gl::GLContext *gl)
{
gl->fGetProgramiv(mName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &mAttribMaxNameLength);
gl->fGetProgramiv(mName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &mUniformMaxNameLength);
gl->fGetProgramiv(mName, LOCAL_GL_ACTIVE_UNIFORMS, &mUniformCount);
gl->fGetProgramiv(mName, LOCAL_GL_ACTIVE_ATTRIBUTES, &mAttribCount);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &mAttribMaxNameLength);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &mUniformMaxNameLength);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORMS, &mUniformCount);
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &mAttribCount);
GLint numVertexAttribs;
if (mContext->MinCapabilityMode()) {
@ -77,9 +77,9 @@ WebGLProgram::UpdateInfo(gl::GLContext *gl)
GLint attrnamelen;
GLint attrsize;
GLenum attrtype;
gl->fGetActiveAttrib(mName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
if (attrnamelen > 0) {
GLint loc = gl->fGetAttribLocation(mName, nameBuf);
GLint loc = gl->fGetAttribLocation(mGLName, nameBuf);
mAttribsInUse[loc] = true;
}
}
@ -515,7 +515,6 @@ WebGLContext::InitAndValidateGL()
mAttribBuffers.Clear();
mUniformTextures.Clear();
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
@ -526,13 +525,6 @@ WebGLContext::InitAndValidateGL()
mBoundFramebuffer = nsnull;
mBoundRenderbuffer = nsnull;
mMapTextures.Clear();
mMapBuffers.Clear();
mMapPrograms.Clear();
mMapShaders.Clear();
mMapFramebuffers.Clear();
mMapRenderbuffers.Clear();
MakeContextCurrent();
// on desktop OpenGL, we always keep vertex attrib 0 array enabled

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

@ -44,8 +44,6 @@ namespace mozilla {
class WebGLExtensionLoseContext;
class WebGLExtensionStandardDerivatives;
#define WEBGLEXTENSIONLOSECONTEXT_PRIVATE_IID \
{0xb0afc2eb, 0x0895, 0x4509, {0x98, 0xde, 0x5c, 0x38, 0x3d, 0x16, 0x06, 0x94}}
class WebGLExtensionLoseContext :
public nsIWebGLExtensionLoseContext,
public WebGLExtension
@ -56,14 +54,8 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLEXTENSIONLOSECONTEXT
NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLEXTENSIONLOSECONTEXT_PRIVATE_IID)
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLExtensionLoseContext, WEBGLACTIVEINFO_PRIVATE_IID)
#define WEBGLEXTENSIONSTANDARDDERIVATIVES_PRIVATE_IID \
{0x3de3dfd9, 0x864a, 0x4e4c, {0x98, 0x9b, 0x29, 0x77, 0xea, 0xa8, 0x0b, 0x7b}}
class WebGLExtensionStandardDerivatives :
public nsIWebGLExtensionStandardDerivatives,
public WebGLExtension
@ -74,12 +66,8 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLEXTENSION
NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLEXTENSIONSTANDARDDERIVATIVES_PRIVATE_IID)
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLExtensionStandardDerivatives, WEBGLACTIVEINFO_PRIVATE_IID)
}
#endif // WEBGLEXTENSIONS_H_

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

@ -1,4 +1,4 @@
This is a local copy of the WebGL conformance suite, SVN revision 15981
This is a local copy of the WebGL conformance suite, SVN revision 16237
The canonical location for this testsuite is:

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

@ -11,13 +11,15 @@ var wtu = WebGLTestUtils;
var canvas;
var gl;
var shouldGenerateGLError;
var extension_name = "WEBKIT_lose_context";
var extension_name = "WEBGL_EXT_lose_context";
var extension;
var bufferObjects;
var program;
var texture;
var texColor = [255, 10, 20, 255];
var allowRestore;
var contextLostEventFired;
var contextRestoredEventFired;
function init()
{
@ -28,15 +30,14 @@ function init()
description("Tests behavior under a restored context.");
shouldGenerateGLError = wtu.shouldGenerateGLError;
runTests();
testLosingContext();
}
function runTests()
function runTest1()
{
testLosingContext();
testLosingAndRestoringContext();
finish();
finishTest();
}
function setupTest()
@ -56,35 +57,75 @@ function setupTest()
function testLosingContext()
{
if (!setupTest())
return;
finishTest();
debug("Test losing a context and inability to restore it.");
canvas.addEventListener("webglcontextlost", testLostContext);
canvas.addEventListener("webglcontextlost", function() {
testLostContext();
// restore the context after this event has exited.
setTimeout(function() {
// we didn't call prevent default so we should not be able to restore the context
shouldGenerateGLError(gl, gl.INVALID_OPERATION, "extension.restoreContext()");
testLosingAndRetoreingContext();
}, 1);
});
canvas.addEventListener("webglcontextrestored", testShouldNotRestoreContext);
allowRestore = false;
contextLostEventFired = false;
contextRestoredEventFired = false;
testOriginalContext();
extension.loseContext();
shouldGenerateGLError(gl, gl.INVALID_OPERATION, "extension.restoreContext()");
debug("");
// The context should be lost immediately.
shouldBeTrue("gl.isContextLost()");
shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
shouldBe("gl.getError()", "gl.NO_ERROR");
// gl methods should be no-ops
shouldGenerateGLError(gl, gl.NO_ERROR, gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP));
// but the event should not have been fired.
shouldBeFalse("contextLostEventFired");
}
function testLosingAndRestoringContext()
{
if (!setupTest())
return;
finishTest();
debug("");
debug("Test losing and restoring a context.");
canvas.addEventListener("webglcontextlost", testLostContext);
canvas.addEventListener("webglcontextrestored", testRestoredContext);
canvas.addEventListener("webglcontextlost", function() {
testLostContext();
// restore the context after this event has exited.
setTimeout(function() {
shouldGenerateGLError(gl, gl.NO_ERROR, "extension.restoreContext()");
// The context should still be lost. It will not get restored until the
// webglrestorecontext event is fired.
shouldBeTrue("gl.isContextLost()");
shouldBe("gl.getError()", "gl.NO_ERROR");
// gl methods should still be no-ops
shouldGenerateGLError(gl, gl.NO_ERROR, gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP));
}, 1);
});
canvas.addEventListener("webglcontextrestored", function() {
testRestoredContext();
finishTest();
});
allowRestore = true;
contextLostEventFired = false;
contextRestoredEventFired = false;
testOriginalContext();
extension.loseContext();
shouldGenerateGLError(gl, gl.NO_ERROR, "extension.restoreContext()");
debug("");
// The context should be lost immediately.
shouldBeTrue("gl.isContextLost()");
shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
shouldBe("gl.getError()", "gl.NO_ERROR");
// gl methods should be no-ops
shouldGenerateGLError(gl, gl.NO_ERROR, gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP));
// but the event should not have been fired.
shouldBeFalse("contextLostEventFired");
}
function testRendering()
@ -118,12 +159,13 @@ function testOriginalContext()
function testLostContext(e)
{
debug("Test lost context");
shouldBeFalse("contextLostEventFired");
contextLostEventFired = true;
shouldBeTrue("gl.isContextLost()");
shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
if (allowRestore)
e.preventDefault();
if (allowRestore)
e.preventDefault();
}
function testShouldNotRestoreContext(e)
@ -147,6 +189,8 @@ function testResources(expected)
function testRestoredContext()
{
debug("Test restored context");
shouldBeFalse("contextRestoredEventFired");
contextRestoredEventFired = true;
shouldBeFalse("gl.isContextLost()");
shouldBe("gl.getError()", "gl.NO_ERROR");
@ -160,16 +204,6 @@ function testRestoredContext()
debug("");
}
function finish() {
successfullyParsed = true;
var epilogue = document.createElement("script");
epilogue.onload = function() {
if (window.nonKhronosFrameworkNotifyDone)
window.nonKhronosFrameworkNotifyDone();
};
epilogue.src = "../../resources/js-test-post.js";
document.body.appendChild(epilogue);
}
</script>
</head>

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

@ -11,7 +11,7 @@ var wtu;
var canvas;
var gl;
var shouldGenerateGLError;
var extension_name = "WEBKIT_lose_context";
var extension_name = "WEBGL_EXT_lose_context";
var extension;
var buffer;
@ -51,7 +51,7 @@ function init()
extension = gl.getExtension(extension_name);
if (!extension) {
debug(extension_name + " extension not found.");
finish();
finishTest();
return;
}
@ -65,8 +65,8 @@ function loseContext()
debug("");
debug("Lose context");
// Note: this will cause the context to be lost, and the
// webglcontextlost event listener to be called, immediately.
// Note: this will cause the context to be lost, but the
// webglcontextlost event listener to be queued.
shouldGenerateGLError(gl, gl.NO_ERROR, "extension.loseContext()");
debug("");
}
@ -302,19 +302,9 @@ function testLostContext()
debug("");
finish();
finishTest();
}
function finish() {
successfullyParsed = true;
var epilogue = document.createElement("script");
epilogue.onload = function() {
if (window.nonKhronosFrameworkNotifyDone)
window.nonKhronosFrameworkNotifyDone();
};
epilogue.src = "../../resources/js-test-post.js";
document.body.appendChild(epilogue);
}
</script>
</head>
<body onload="init()">

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

@ -3,4 +3,6 @@ oes-texture-float.html
oes-vertex-array-object.html
webgl-debug-renderer-info.html
webgl-debug-shaders.html
# commented out until 1.0.1 cut
# webgl-experimental-compressed-textures.html

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

@ -0,0 +1,3 @@
var img_4x4_rgb_dxt1 = [
0xe0,0x07,0x00,0xf8,0x11,0x10,0x15,0x00,
];

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

@ -0,0 +1,3 @@
var img_4x4_rgba_dxt1 = [
0xe0,0x07,0x00,0xf8,0x13,0x10,0x15,0x00,
];

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

@ -0,0 +1,3 @@
var img_4x4_rgba_dxt3 = [
0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,
];

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

@ -0,0 +1,3 @@
var img_4x4_rgba_dxt5 = [
0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,
];

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

@ -0,0 +1,3 @@
var img_4x4_rgba_raw = [
0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgb_dxt1 = [
0xe0,0x07,0x00,0xf8,0x11,0x10,0x15,0x00,0x1f,0x00,0xe0,0xff,0x11,0x10,0x15,0x00,0xe0,0x07,0x1f,0xf8,0x44,0x45,0x40,0x55,0x1f,0x00,0xff,0x07,0x44,0x45,0x40,0x55,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgba_dxt1 = [
0xe0,0x07,0x00,0xf8,0x13,0x13,0x15,0x00,0x1f,0x00,0xe0,0xff,0x11,0x10,0x15,0x00,0xe0,0x07,0x1f,0xf8,0x44,0x45,0x43,0x57,0x1f,0x00,0xff,0x07,0x44,0x45,0x40,0x55,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgba_dxt3 = [
0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xff,0x1f,0x00,0x44,0x45,0x40,0x55,0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x1f,0xf8,0xe0,0x07,0x11,0x10,0x15,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x1f,0x00,0x11,0x10,0x15,0x00,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgba_dxt5 = [
0xff,0x69,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x1f,0x00,0x44,0x45,0x40,0x55,0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x1f,0xf8,0xe0,0x07,0x11,0x10,0x15,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0x1f,0x00,0x11,0x10,0x15,0x00,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgba_pvrtc4bpp = [
0x33,0x30,0x3f,0x00,0xe0,0x83,0x00,0xfc,0xcc,0xcf,0xc0,0xff,0xe0,0x83,0x1f,0xfc,0xcc,0xcf,0xc0,0xff,0xe0,0xff,0x1f,0x80,0x33,0x30,0x3f,0x00,0xfe,0x83,0x1f,0x80,
];

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

@ -0,0 +1,3 @@
var img_8x8_rgba_raw = [
0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x69,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,
];

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

@ -0,0 +1,520 @@
<!--
Copyright (c) 2011 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL WEBGL_EXPERIMENTAL_compressed_textures Conformance Tests</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<style>
img {
border: 1px solid black;
margin-right: 1em;
}
.testimages {
}
.testimages br {
clear: both;
}
.testimages > div {
float: left;
margin: 1em;
}
</style>
<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
<script src="../../resources/js-test-pre.js"></script>
<script src="../resources/webgl-test.js"></script>
<script src="../resources/webgl-test-utils.js"></script>
<script src="compressed-textures/4x4.rgb.dxt1.js"></script>
<script src="compressed-textures/4x4.rgba.dxt1.js"></script>
<script src="compressed-textures/4x4.rgba.dxt5.js"></script>
<script src="compressed-textures/8x8.rgb.dxt1.js"></script>
<script src="compressed-textures/8x8.rgba.dxt1.js"></script>
<script src="compressed-textures/8x8.rgba.dxt5.js"></script>
<script src="compressed-textures/8x8.rgba.pvrtc4bpp.js"></script>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
<div id="console"></div>
<!-- Shaders for testing standard derivatives -->
<script>
description("This test verifies the functionality of the OES_vertex_array_object extension, if it is available.");
debug("");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, {antialias: false});
var program = wtu.setupTexturedQuad(gl);
var ext = null;
var vao = null;
var validFormats = {
COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
ETC1_RGB8_OES : 0x8D64,
COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0x8C00,
COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0x8C02
};
var name;
var supportedFormats;
if (!gl) {
testFailed("WebGL context does not exist");
} else {
testPassed("WebGL context exists");
// Run tests with extension disabled
runTestDisabled();
// Query the extension and store globally so shouldBe can access it
ext = gl.getExtension("WEBGL_EXPERIMENTAL_compressed_textures");
if (!ext) {
testPassed("No WEBGL_EXPERIMENTAL_compressed_textures support -- this is legal");
runSupportedTest(false);
} else {
testPassed("Successfully enabled WEBGL_EXPERIMENTAL_compressed_textures extension");
runSupportedTest(true);
runTestExtension();
}
}
function runSupportedTest(extensionEnabled) {
var supported = gl.getSupportedExtensions();
if (supported.indexOf("WEBGL_EXPERIMENTAL_compressed_textures") >= 0) {
if (extensionEnabled) {
testPassed("WEBGL_EXPERIMENTAL_compressed_textures listed as supported and getExtension succeeded");
} else {
testFailed("WEBGL_EXPERIMENTAL_compressed_textures listed as supported but getExtension failed");
}
} else {
if (extensionEnabled) {
testFailed("WEBGL_EXPERIMENTAL_compressed_textures not listed as supported but getExtension succeeded");
} else {
testPassed("WEBGL_EXPERIMENTAL_compressed_textures not listed as supported and getExtension failed -- this is legal");
}
}
}
function runTestDisabled() {
debug("Testing binding enum with extension disabled");
// Default value is null
if (gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS) === null) {
testPassed("Default value of COMPRESSED_TEXTURE_FORMATS is null");
} else {
testFailed("Default value of COMPRESSED_TEXTURE_FORMATS is not null");
}
}
function checkIsValidFormat(format) {
for (var name in validFormats) {
if (format == validFormats[name]) {
testPassed("supported format " + formatToString(format) + " is valid");
return;
}
}
testFailed("supported format " + formatToString(format) + " is not valid");
}
function formatToString(format) {
for (var p in ext) {
if (ext[p] == format) {
return p;
}
}
return "0x" + format.toString(16);
}
function runTestExtension() {
debug("Testing WEBGL_EXPERIMENTAL_compressed_textures");
// check that all format enums exist.
for (name in validFormats) {
var expected = "0x" + validFormats[name].toString(16);
var actual = "ext['" + name + "']";
shouldBe(actual, expected);
}
supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
// Even if no formats are supported this should return an array.
shouldBeTrue("supportedFormats.length !== undefined");
// check that each format is an allowed format
for (var ii = 0; ii < supportedFormats.length; ++ii) {
checkIsValidFormat(supportedFormats[ii]);
}
// Test each format
for (var ii = 0; ii < supportedFormats.length; ++ii) {
switch (supportedFormats[ii]) {
case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
testDXT1_RGB();
break;
case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
testDXT1_RGBA();
break;
case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
testDXT5_RGBA();
break;
case ext.ETC1_RGB8_OES:
testETC1_RGB8();
break;
case ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
testPVRTC_RGB_4BPPV1();
break;
case ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
testPVRTC_RGBA_4BPPV1();
break;
}
}
}
function testDXT1_RGB() {
var tests = [
{ width: 4,
height: 4,
channels: 3,
data: img_4x4_rgb_dxt1,
format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT
},
{ width: 8,
height: 8,
channels: 3,
data: img_8x8_rgb_dxt1,
format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT
}
];
testDXTTextures(tests);
}
function testDXT1_RGBA() {
var tests = [
{ width: 4,
height: 4,
channels: 4,
data: img_4x4_rgba_dxt1,
format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT
},
{ width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_dxt1,
format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT
}
];
testDXTTextures(tests);
}
function testDXT5_RGBA() {
var tests = [
{ width: 4,
height: 4,
channels: 4,
data: img_4x4_rgba_dxt5,
format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT
},
{ width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_dxt5,
format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT
}
];
testDXTTextures(tests);
}
function testETC1_RGB8() {
testFailed("ETC1 test not yet implemented");
}
function testPVRTC_RGB_4BPPV1() {
var tests = [
{ width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_pvrtc4bpp,
format: ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG
}
];
testPVRTCTextures(tests);
}
function testPVRTC_RGB_4BPPV1() {
var tests = [
{ width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_pvrtc4bpp,
format: ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
}
];
testPVRTCTextures(tests);
}
function testDXTTextures(tests) {
debug("<hr/>");
for (var ii = 0; ii < tests.length; ++ii) {
testDXTTexture(tests[ii]);
}
}
function uncompressDXTBlock(
destBuffer, destX, destY, destWidth, src, srcOffset, format) {
function make565(src, offset) {
return src[offset + 0] + src[offset + 1] * 256;
}
function make8888From565(c) {
return [
Math.floor(((c >> 11) & 0x1F) * 255 / 31),
Math.floor(((c >> 5) & 0x3F) * 255 / 63),
Math.floor(((c >> 0) & 0x1F) * 255 / 31),
255
];
}
function mix(mult, c0, c1, div) {
var r = [];
for (var ii = 0; ii < c0.length; ++ii) {
r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div);
}
return r;
}
var colorOffset =
srcOffset + ((format == ext.COMPRESSED_RGBA_S3TC_DXT5_EXT) ? 8 : 0);
var color0 = make565(src, colorOffset + 0);
var color1 = make565(src, colorOffset + 2);
var c0gtc1 = color0 > color1 || format == ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
var rgba0 = make8888From565(color0);
var rgba1 = make8888From565(color1);
var colors = [
rgba0,
rgba1,
c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
];
// yea I know there is a lot of math in this inner loop.
// so sue me.
for (var yy = 0; yy < 4; ++yy) {
var pixels = src[colorOffset + 4 + yy];
for (var xx = 0; xx < 4; ++xx) {
var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
var code = (pixels >> (xx * 2)) & 0x3;
var srcColor = colors[code];
var alpha;
switch (format) {
case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
alpha = 255;
break;
case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
alpha = (code == 3 && !c0gtc1) ? 0 : 255;
break;
case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
{
var alpha0 = src[srcOffset + 0];
var alpha1 = src[srcOffset + 1];
var alphaOff = Math.floor(yy / 2) * 3 + 2;
var alphaBits =
src[srcOffset + alphaOff + 0] +
src[srcOffset + alphaOff + 1] * 256 +
src[srcOffset + alphaOff + 2] * 65536;
var alphaShift = (yy % 2) * 12 + xx * 3;
var alphaCode = (alphaBits >> alphaShift) & 0x7;
if (alpha0 > alpha1) {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
default:
alpha = ((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7;
break;
}
} else {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
case 6:
alpha = 0;
break;
case 7:
alpha = 255;
break;
default:
alpha = ((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5;
break;
}
}
}
break;
default:
throw "bad format";
}
destBuffer[dstOff + 0] = srcColor[0];
destBuffer[dstOff + 1] = srcColor[1];
destBuffer[dstOff + 2] = srcColor[2];
destBuffer[dstOff + 3] = alpha;
}
}
}
function uncompressDXT(width, height, data, format) {
if (width % 4 || height % 4) throw "bad width or height";
var dest = new Uint8Array(width * height * 4);
var blocksAcross = width / 4;
var blocksDown = height / 4;
var blockSize = (format == ext.COMPRESSED_RGBA_S3TC_DXT5_EXT ? 16 : 8);
for (var yy = 0; yy < blocksDown; ++yy) {
for (var xx = 0; xx < blocksAcross; ++xx) {
uncompressDXTBlock(
dest, xx * 4, yy * 4, width, data,
(yy * blocksAcross + xx) * blockSize, format);
}
}
return dest;
}
function testDXTTexture(test) {
var uncompressedData = uncompressDXT(
test.width, test.height, test.data, test.format);
var inner = 4; //test.width == 4 ? 4 : 1
for (var ii = 0; ii < inner; ++ii) {
var width = test.width - ii;
var height = test.height - ii;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
debug("testing " + formatToString(test.format) + " " +
width + "x" + height);
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
ext.compressedTexImage2D(
gl.TEXTURE_2D, 0, test.format, width, height, 0,
new Uint8Array(test.data));
glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
wtu.drawQuad(gl);
compareRect(
width, height, test.channels, test.width, test.height, uncompressedData,
test.data, test.format);
}
gl.compressedTexImage2D(
gl.TEXTURE_2D, 0, test.format, width + 1, height, 0,
new Uint8Array(test.data));
glErrorShouldBe(
gl, gl.INVALID_OPERATION, "data size does not match dimensions");
// TODO: test compressedTexSubImage2D
// TODO: test invalid width, height, xoffset, yoffset
}
function insertImg(element, caption, img) {
var div = document.createElement("div");
div.appendChild(img);
var label = document.createElement("div");
label.appendChild(document.createTextNode(caption));
div.appendChild(label);
element.appendChild(div);
}
function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
var scale = 8;
var c = document.createElement("canvas");
c.width = imageWidth * scale;
c.height = imageHeight * scale;
var ctx = c.getContext("2d");
for (var yy = 0; yy < imageWidth; ++yy) {
for (var xx = 0; xx < imageHeight; ++xx) {
var offset = (yy * dataWidth + xx) * 4;
ctx.fillStyle = "rgba(" +
data[offset + 0] + "," +
data[offset + 1] + "," +
data[offset + 2] + "," +
(alpha ? data[offset + 3] / 255 : 1) + ")";
ctx.fillRect(xx * scale, yy * scale, scale, scale);
}
}
var img = document.createElement("img");
img.src = c.toDataURL();
return img;
}
function compareRect(
actualWidth, actualHeight, actualChannels,
dataWidth, dataHeight, expectedData,
testData, testFormat) {
var actual = new Uint8Array(actualWidth * actualHeight * 4);
gl.readPixels(
0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
var div = document.createElement("div");
div.className = "testimages";
insertImg(div, "expected", makeImage(
actualWidth, actualHeight, dataWidth, expectedData,
actualChannels == 4));
insertImg(div, "actual", makeImage(
actualWidth, actualHeight, actualWidth, actual,
actualChannels == 4));
div.appendChild(document.createElement('br'));
document.getElementById("console").appendChild(div);
var failed = false;
for (var yy = 0; yy < actualHeight; ++yy) {
for (var xx = 0; xx < actualWidth; ++xx) {
var actualOffset = (yy * actualWidth + xx) * 4;
var expectedOffset = (yy * dataWidth + xx) * 4;
var expected = [
expectedData[expectedOffset + 0],
expectedData[expectedOffset + 1],
expectedData[expectedOffset + 2],
(actualChannels == 3 ? 255 : expectedData[expectedOffset + 3])
];
for (var jj = 0; jj < 4; ++jj) {
if (actual[actualOffset + jj] != expected[jj]) {
failed = true;
var was = actual[actualOffset + 0].toString();
for (j = 1; j < 4; ++j) {
was += "," + actual[actualOffset + j];
}
testFailed('at (' + xx + ', ' + yy +
') expected: ' + expected + ' was ' + was);
}
}
}
}
if (!failed) {
testPassed("texture rendered correctly");
}
}
function testPVRTCTextures() {
testFailed("PVRTC test not yet implemented");
}
debug("");
successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>

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

@ -25,6 +25,7 @@ GLSLGenerator.runFeatureTest({
args: "$(type) p1, $(type) p2",
baseArgs: "value$(field)",
testFunc: "$(func)($(type),$(type))",
fragmentTolerance: 1,
emuFuncs: [
{ type: "float",
code: [

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

@ -25,6 +25,7 @@ GLSLGenerator.runFeatureTest({
args: "$(type) value",
baseArgs: "value$(field)",
testFunc: "$(func)($(type))",
fragmentTolerance: 1,
emuFuncs: [
{ type: "float",
code: [

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

@ -24,6 +24,7 @@ GLSLGenerator.runFeatureTest({
args: "$(type) value, float divisor",
baseArgs: "value$(field), divisor",
testFunc: "$(func)($(arg0), float)",
fragmentTolerance: 1,
emuFunc: ["float $(func)_base(float value, float divisor) {",
" return value - divisor * floor(value / divisor);",
"}"].join("\n"),

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

@ -32,6 +32,7 @@ var fragmentShader = wtu.loadStandardFragmentShader(gl);
assertMsg(fragmentShader, "fragment shader loaded");
var program = gl.createProgram();
shouldBeTrue("program != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.attachShader(program, vertexShader)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.attachShader(program, fragmentShader)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.linkProgram(program)");
@ -56,13 +57,18 @@ debug("");
debug("texture deletion");
var fbo = gl.createFramebuffer(), fbo2 = gl.createFramebuffer(), fbo3 = gl.createFramebuffer();
shouldBeTrue("fbo != null");
shouldBeTrue("fbo2 != null");
shouldBeTrue("fbo3 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
var tex = gl.createTexture();
shouldBeTrue("tex != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.TEXTURE");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
// Deleting a texture bound to the currently-bound fbo is the same as
// detaching the textue from fbo first, then delete the texture.
@ -74,6 +80,7 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
var texCubeMap = gl.createTexture();
shouldBeTrue("texCubeMap != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCubeMap)");
shouldBe("gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP)", "texCubeMap");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(texCubeMap)");
@ -83,16 +90,33 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_CUBE_MAP, texC
shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP)");
var t = gl.createTexture();
shouldBeTrue("t != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(t)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t)");
shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)");
var t2 = gl.createTexture();
shouldBeTrue("t2 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t2)");
shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "t2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, t2)");
shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "t2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(t2)");
shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)");
shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
debug("");
debug("renderbuffer deletion");
var rbo = gl.createRenderbuffer(), rbo2 = gl.createRenderbuffer(), rbo3 = gl.createRenderbuffer();
shouldBeTrue("rbo != null");
shouldBeTrue("rbo2 != null");
shouldBeTrue("rbo3 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
@ -111,10 +135,179 @@ shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo3)");
shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
debug("");
debug("using deleted renderbuffer");
rbo = gl.createRenderbuffer();
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
// make backbuffer red
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// make fbo green
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
// delete renderbuffer. It should still be attached to fbo though.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
// Use fbo that has deleted rbo.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue")');
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
}
debug("");
debug("renderbuffer attached twice to same framebuffer");
rbo = gl.createRenderbuffer();
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
var rbo2 = gl.createRenderbuffer();
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo2)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
// attach rbo2 at two attachment points incompatible with it
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rbo2)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo2)");
shouldBeTrue("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) == rbo2");
shouldBeTrue("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) == rbo2");
// fbo can't be complete as rbo2 is attached at incompatible attachment points
shouldBeFalse("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE");
// now we delete rbo2, which detaches it from the two attachment points where it currently is attached
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo2)");
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
// we should now be in the same state as before with only rbo attached, so fbo should be complete again
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
shouldBeTrue("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) == rbo");
}
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
debug("");
debug("using deleted texture");
tex = gl.createTexture();
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
// make fbo green
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
// delete texture. It should still be attached to fbo though.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255,0,0,255], "backbuffer should be red")');
// Use fbo that has deleted texture.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue")');
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
}
debug("");
debug("using deleted renderbuffer");
rbo = gl.createRenderbuffer();
shouldBeTrue("rbo != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
// make backbuffer red
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// make fbo green
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// delete renderbuffer. It should still be attached to fbo2 though.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
// fbo has no attachments
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
// Use fbo2 that has deleted rbo.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue")');
shouldBeTrue("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) == rbo");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
shouldGenerateGLError(gl, gl.NONE, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
}
debug("");
debug("using deleted texture");
tex = gl.createTexture();
shouldBeTrue("tex != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
// make fbo green
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// delete texture. It should still be attached to fbo2 though.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
// fbo has no attachments
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
// Use fbo that has deleted texture.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue")');
shouldBeTrue("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) == tex");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
}
debug("");
debug("buffer deletion");
var buffer = gl.createBuffer();
shouldBeTrue("buffer != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)");
shouldBe("gl.getParameter(gl.ARRAY_BUFFER_BINDING)", "buffer");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(buffer)");
@ -123,7 +316,19 @@ shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)");
shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
var buffer2 = gl.createBuffer();
shouldBeTrue("buffer2 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer2)");
shouldBe("gl.getParameter(gl.ARRAY_BUFFER_BINDING)", "buffer2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, null)");
shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(buffer2)");
shouldBeFalse("gl.isBuffer(buffer2)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer2)");
shouldBeNull("gl.getParameter(gl.ARRAY_BUFFER_BINDING)");
var bufferElement = gl.createBuffer();
shouldBeTrue("bufferElement != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferElement)");
shouldBe("gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING)", "bufferElement");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(bufferElement)");
@ -133,12 +338,35 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, b
shouldBeNull("gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING)");
var b = gl.createBuffer();
shouldBeTrue("b != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b)");
shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW)");
var b1 = gl.createBuffer();
shouldBeTrue("b1 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b1);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(1);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);");
var b2 = gl.createBuffer();
shouldBeTrue("b2 != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, b2);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(2);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(2, 4, gl.FLOAT, false, 0, 0);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.enableVertexAttribArray(3);");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.vertexAttribPointer(3, 4, gl.FLOAT, false, 0, 0);");
shouldBe("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b1");
shouldBe("gl.getVertexAttrib(2, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b2");
shouldBe("gl.getVertexAttrib(3, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b2);");
shouldBe("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)", "b1");
shouldBeNull("gl.getVertexAttrib(2, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
shouldBeNull("gl.getVertexAttrib(3, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteBuffer(b1);");
shouldBeNull("gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)");
debug("");
debug("framebuffer deletion");
@ -154,6 +382,41 @@ shouldBe("gl.getParameter(gl.FRAMEBUFFER_BINDING)", "fbo2");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fbo3)");
shouldBe("gl.getParameter(gl.FRAMEBUFFER_BINDING)", "fbo2");
fbo = gl.createFramebuffer();
rbo = gl.createRenderbuffer();
shouldBeTrue("fbo != null");
shouldBeTrue("rbo != null");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
// set backbuffer to red
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(1,0,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// set framebuffer to green
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
// check framebuffer
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 16, 16, 1, 1, [0,0,0,0], "outside fbo should be black")');
// delete framebuffer. because this was the bound fbo the backbuffer should be active now
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteFramebuffer(fbo)");
// check backbuffer
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [255,0,0,255], "backbuffer should be red")');
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 300, 0, 300, 300, [0,0,0,0], "outside backbuffer should be black")');
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 150, 300, 300, [0,0,0,0], "outside backbuffer should be black")');
// check drawing to backbuffer
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,1,0,1)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green")');
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
// check again because many buggy implementations will have bound to the true backbuffer on deleteFramebuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green")');
}
successfullyParsed = true;
</script>

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

@ -59,7 +59,7 @@ uniform vec4 foo;
varying vec4 texCoord0;
void main()
{
gl_FragColor = vec4(foo.r/256.0, foo.g/256.0, foo.b/256.0, foo.a*texCoord0.z/256.0);
gl_FragColor = vec4(foo.r/255.0, foo.g/255.0, foo.b/255.0, foo.a*texCoord0.z/255.0);
}
</script>
<style>canvas{ position:absolute; }</style>

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

@ -82,10 +82,10 @@ varying vec4 texCoord0;
void main()
{
gl_FragColor = vec4(
uniV4[0].r/256.0,
uniV4[0].g/256.0,
uniV4[0].b/256.0,
uniV4[0].a*texCoord0.z/256.0);
uniV4[0].r/255.0,
uniV4[0].g/255.0,
uniV4[0].b/255.0,
uniV4[0].a*texCoord0.z/255.0);
}
</script>
<style>canvas{ position:absolute; }</style>

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

@ -87,10 +87,10 @@ varying vec4 texCoord0;
void main()
{
gl_FragColor = vec4(
uniV4.r/256.0,
uniV4.g/256.0,
uniV4.b/256.0,
uniV4.a*texCoord0.z/256.0);
uniV4.r/255.0,
uniV4.g/255.0,
uniV4.b/255.0,
uniV4.a*texCoord0.z/255.0);
}
</script>
<style>canvas{ position:absolute; }</style>

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

@ -27,29 +27,43 @@ var colorBuffer;
var width;
var height;
function testAttachment(attachment, buffer, isConflicted)
const ALLOW_COMPLETE = 0x01;
const ALLOW_UNSUPPORTED = 0x02;
const ALLOW_INCOMPLETE_ATTACHMENT = 0x04;
function CheckFramebufferForAllowedStatuses(allowedStatuses)
{
// If the framebuffer is in an error state for multiple reasons,
// we can't guarantee which one will be reported.
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
var statusAllowed = ((allowedStatuses & ALLOW_COMPLETE) && (status == gl.FRAMEBUFFER_COMPLETE)) ||
((allowedStatuses & ALLOW_UNSUPPORTED) && (status == gl.FRAMEBUFFER_UNSUPPORTED)) ||
((allowedStatuses & ALLOW_INCOMPLETE_ATTACHMENT) && (status == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
var msg = "gl.checkFramebufferStatus(gl.FRAMEBUFFER) returned " + status;
if (statusAllowed)
testPassed(msg);
else
testFailed(msg);
}
function testAttachment(attachment, buffer, allowedStatuses)
{
shouldBeNonNull("fbo = gl.createFramebuffer()");
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, buffer);
glErrorShouldBe(gl, gl.NO_ERROR);
// If the framebuffer is in an error state for multiple reasons,
// we can't guarantee which one will be reported.
if ((width == 0 || height == 0) && !isConflicted) {
// Zero-sized renderbuffers are supposed to result in an incomplete attachment.
// However, certain combination may violate implementation specific restrictions.
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT || gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_UNSUPPORTED");
} else if (isConflicted) {
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_UNSUPPORTED");
CheckFramebufferForAllowedStatuses(allowedStatuses);
if ((allowedStatuses & ALLOW_COMPLETE) == 0) {
gl.clear(gl.COLOR_BUFFER_BIT);
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(width * height * 4));
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
}
gl.deleteFramebuffer(fbo);
}
function testAttachments(attachment0, buffer0, attachment1, buffer1, isConflicted)
function testAttachments(attachment0, buffer0, attachment1, buffer1, allowedStatuses)
{
shouldBeNonNull("fbo = gl.createFramebuffer()");
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
@ -58,27 +72,20 @@ function testAttachments(attachment0, buffer0, attachment1, buffer1, isConflicte
glErrorShouldBe(gl, gl.NO_ERROR);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment1, gl.RENDERBUFFER, buffer1);
glErrorShouldBe(gl, gl.NO_ERROR);
// If the framebuffer is in an error state for multiple reasons,
// we can't guarantee which one will be reported.
if ((width == 0 || height == 0) && !isConflicted) {
// Zero-sized renderbuffers are supposed to result in an incomplete attachment.
// However, certain combination may violate implementation specific restrictions.
shouldBeTrue("gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT || gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_UNSUPPORTED");
} else if (isConflicted) {
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_UNSUPPORTED");
}
CheckFramebufferForAllowedStatuses(allowedStatuses);
gl.deleteFramebuffer(fbo);
}
function testColorRenderbuffer(internalformat)
function testColorRenderbuffer(internalformat, allowedStatuses)
{
shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, internalformat, width, height);
glErrorShouldBe(gl, gl.NO_ERROR);
testAttachment(gl.COLOR_ATTACHMENT0, colorBuffer, false);
testAttachment(gl.COLOR_ATTACHMENT0, colorBuffer, allowedStatuses);
}
function testDepthStencilRenderbuffer()
function testDepthStencilRenderbuffer(allowedStatuses)
{
shouldBeNonNull("depthStencilBuffer = gl.createRenderbuffer()");
gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
@ -103,7 +110,7 @@ function testDepthStencilRenderbuffer()
shouldBeTrue("gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_STENCIL_SIZE) > 0");
}
glErrorShouldBe(gl, gl.NO_ERROR);
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, false);
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatuses);
}
description("Test framebuffer object attachment behaviors");
@ -134,49 +141,59 @@ for (width = 0; width <= 2; width += 2)
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
glErrorShouldBe(gl, gl.NO_ERROR);
var allowedStatusForGoodCase
= (width == 0 || height == 0) ? ALLOW_INCOMPLETE_ATTACHMENT : ALLOW_COMPLETE;
// some cases involving stencil seem to be implementation-dependent
var allowedStatusForImplDependentCase = allowedStatusForGoodCase | ALLOW_UNSUPPORTED;
debug("Attach depth using DEPTH_ATTACHMENT");
testAttachment(gl.DEPTH_ATTACHMENT, depthBuffer, false);
testAttachment(gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForGoodCase);
debug("Attach depth using STENCIL_ATTACHMENT");
testAttachment(gl.STENCIL_ATTACHMENT, depthBuffer, true);
testAttachment(gl.STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
debug("Attach depth using DEPTH_STENCIL_ATTACHMENT");
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthBuffer, true);
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
debug("Attach stencil using STENCIL_ATTACHMENT");
testAttachment(gl.STENCIL_ATTACHMENT, stencilBuffer, false);
testAttachment(gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForImplDependentCase);
debug("Attach stencil using DEPTH_ATTACHMENT");
testAttachment(gl.DEPTH_ATTACHMENT, stencilBuffer, true);
testAttachment(gl.DEPTH_ATTACHMENT, stencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
debug("Attach stencil using DEPTH_STENCIL_ATTACHMENT");
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, stencilBuffer, true);
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, stencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
debug("Attach depthStencil using DEPTH_STENCIL_ATTACHMENT");
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, false);
testAttachment(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForGoodCase);
debug("Attach depthStencil using DEPTH_ATTACHMENT");
testAttachment(gl.DEPTH_ATTACHMENT, depthStencilBuffer, true);
testAttachment(gl.DEPTH_ATTACHMENT, depthStencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
debug("Attach depthStencil using STENCIL_ATTACHMENT");
testAttachment(gl.STENCIL_ATTACHMENT, depthStencilBuffer, true);
testAttachment(gl.STENCIL_ATTACHMENT, depthStencilBuffer, ALLOW_INCOMPLETE_ATTACHMENT);
var allowedStatusForConflictedAttachment
= (width == 0 || height == 0) ? ALLOW_UNSUPPORTED | ALLOW_INCOMPLETE_ATTACHMENT
: ALLOW_UNSUPPORTED;
debug("Attach depth, then stencil, causing conflict");
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, true);
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForConflictedAttachment);
debug("Attach stencil, then depth, causing conflict");
testAttachments(gl.STENCIL_ATTACHMENT, stencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, true);
testAttachments(gl.STENCIL_ATTACHMENT, stencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment);
debug("Attach depth, then depthStencil, causing conflict");
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, true);
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForConflictedAttachment);
debug("Attach depthStencil, then depth, causing conflict");
testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, true);
testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.DEPTH_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment);
debug("Attach stencil, then depthStencil, causing conflict");
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, true);
testAttachments(gl.DEPTH_ATTACHMENT, depthBuffer, gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, allowedStatusForConflictedAttachment);
debug("Attach depthStencil, then stencil, causing conflict");
testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, true);
testAttachments(gl.DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer, gl.STENCIL_ATTACHMENT, stencilBuffer, allowedStatusForConflictedAttachment);
debug("Attach color renderbuffer with internalformat == RGBA4");
testColorRenderbuffer(gl.RGBA4);
testColorRenderbuffer(gl.RGBA4, allowedStatusForGoodCase);
debug("Attach color renderbuffer with internalformat == RGB5_A1");
testColorRenderbuffer(gl.RGB5_A1);
testColorRenderbuffer(gl.RGB5_A1, allowedStatusForGoodCase);
debug("Attach color renderbuffer with internalformat == RGB565");
testColorRenderbuffer(gl.RGB565);
testColorRenderbuffer(gl.RGB565, allowedStatusForGoodCase);
debug("Create and attach depthStencil renderbuffer");
testDepthStencilRenderbuffer();
testDepthStencilRenderbuffer(allowedStatusForGoodCase);
}
}
@ -266,23 +283,35 @@ function testUsingIncompleteFramebuffer() {
debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
testRenderingAndReading();
shouldBeNonNull("fbo = gl.createFramebuffer()");
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
shouldBeNonNull("fbo2 = gl.createFramebuffer()");
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2);
CheckFramebuffer(gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
debug("");
debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
testRenderingAndReading();
shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0);
debug("");
debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
testRenderingAndReading();
function testRenderingAndReading() {
glErrorShouldBe(gl, gl.NO_ERROR);
wtu.drawQuad(gl);
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "drawArrays with incomplete framebuffer");
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "readPixels from incomplete framebuffer");
// copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
// the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
// the framebuffer is not of a compatible type.
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D from incomplete framebuffer");
glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], "copyTexImage2D from incomplete framebuffer");
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 1, 1, 0);
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D from incomplete framebuffer");
glErrorShouldBe(gl, [gl.INVALID_FRAMEBUFFER_OPERATION, gl.INVALID_OPERATION], "copyTexSubImage2D from incomplete framebuffer");
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "clear with incomplete framebuffer");
}

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

@ -6,4 +6,4 @@ gl-scissor-test.html
more-than-65536-indices.html
point-size.html
triangle.html
line-loop-tri-fan.html

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

@ -0,0 +1,238 @@
<!--
Copyright (C) 2011 Opera Software ASA. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY OPERA SOFTWARE ASA. ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../resources/js-test-pre.js"></script>
<script src="../resources/webgl-test.js"></script>
<script id="vshader" type="x-shader/x-vertex">
attribute vec2 pos;
void main()
{
gl_Position = vec4(pos, 0, 1);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
void main()
{
gl_FragColor = vec4(0, 1, 0, 1);
}
</script>
<script>
// Check a single 32-bit RGBA pixel.
function checkPixel(buf, index, correct) {
for (var i = 0; i < 4; ++i) {
if (buf[index + i] != correct[i]) {
return false;
}
}
return true;
}
// Check the line loop by reading the pixels and making sure just the edge
// pixels are green and the rest are black.
function checkLineLoop(gl, w) {
var buf = new Uint8Array(w * w * 4);
gl.readPixels(0, 0, w, w, gl.RGBA, gl.UNSIGNED_BYTE, buf);
var green = [0,255,0,255];
var black = [0,0,0,255];
var isCorrect = true;
for (var j = 0; j < w * w * 4; j += 4) {
var correct = black;
if (j < w * 4 || j > w * (w - 1) * 4 || j % (w * 4) == 0 || j % (w * 4) == (w - 1) * 4) {
correct = green;
}
if (!checkPixel(buf, j, correct)) {
isCorrect = false;
break;
}
}
if (isCorrect) {
testPassed("Line loop was drawn correctly.");
} else {
testFailed("Line loop was drawn incorrectly.");
}
}
// Check the tri fan by reading the pixels and making sure they are all green.
function checkTriFan(gl, w) {
buf = new Uint8Array(w * w * 4);
gl.readPixels(0, 0, w, w, gl.RGBA, gl.UNSIGNED_BYTE, buf);
var filled = true;
for (var j = 0; j < w * w * 4; j += 4) {
if (!checkPixel(buf, j, [0,255,0,255])) {
filled = false;
break;
}
}
if (filled) {
testPassed("Triangle fan was drawn correctly.");
} else {
testFailed("Triangle fan was drawn incorrectly.");
}
}
function runTest()
{
var gl = initWebGL('testbed', 'vshader', 'fshader', ['pos'], [0, 0, 0, 1], 1, { antialias: false });
if (!gl) {
testFailed('initWebGL(..) failed');
return;
}
var w = document.getElementById('testbed').width;
gl.enableVertexAttribArray(0);
//---------- LINE_LOOP----------
var d = 1/w;
var vertices = new Float32Array([-1+d, -1+d, 1-d, -1+d, 1-d, 1-d, -1+d, 1-d]);
var vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
var indBuf = gl.createBuffer();
var indices = new Uint16Array([0, 1, 2, 3]);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
debug('Draw a square using a line loop and verify that it draws all four sides and nothing else.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.LINE_LOOP, 0, vertices.length / 2);
checkLineLoop(gl, w);
debug('Draw a square using an indexed line loop and verify that it draws all four sides and nothing else.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.LINE_LOOP, indices.length, gl.UNSIGNED_SHORT, 0);
checkLineLoop(gl, w);
vertices = new Float32Array([0, 0, 0, 0, 0, 0, -1+d, -1+d, 1-d, -1+d, 1-d, 1-d, -1+d, 1-d]);
vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
indBuf = gl.createBuffer();
indices = new Uint16Array([0, 1, 2, 3, 4, 5, 6]);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
debug('Draw a square using a line loop with a vertex buffer offset and verify that it draws all four sides and nothing else.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.LINE_LOOP, 3, vertices.length / 2 - 3);
checkLineLoop(gl, w);
debug('Draw a square using an indexed line loop with an index buffer offset and verify that it draws all four sides and nothing else.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.LINE_LOOP, indices.length - 3, gl.UNSIGNED_SHORT, 3 * 2);
checkLineLoop(gl, w);
//---------- LINE_LOOP UBYTE ----------
var degenVerts = new Array(252 * 2);
for (var j = 0; j < 252 * 2; ++j) {
degenVerts[j] = -1+d;
}
degenVerts = degenVerts.concat([-1+d, -1+d, 1-d, -1+d, 1-d, 1-d, -1+d, 1-d]);
vertices = new Float32Array(degenVerts);
vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
indBuf = gl.createBuffer();
var degenInd = new Array(252);
for (var j = 0; j < 252; ++j) {
degenInd[j] = j;
}
degenInd = degenInd.concat([252, 253, 254, 255]);
indices = new Uint8Array(degenInd);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
debug('Draw a square using an ubyte indexed line loop with 256 indices and verify that it draws all four sides and nothing else.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.LINE_LOOP, indices.length, gl.UNSIGNED_BYTE, 0);
checkLineLoop(gl, w);
//---------- TRIANGLE_FAN ----------
vertices = new Float32Array([0, 0, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1]);
vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
indices = new Uint16Array([0,1,2,3,4,5]);
indBuf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
debug('Draw a filled square using a triangle fan and verify that it fills the entire canvas.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertices.length / 2);
checkTriFan(gl, w);
debug('Draw a filled square using an indexed triangle fan and verify that it fills the entire canvas.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLE_FAN, indices.length, gl.UNSIGNED_SHORT, 0);
checkTriFan(gl, w);
vertices = new Float32Array([1, 1, 1, 1, 1, 1, 0, 0, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1]);
vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
indices = new Uint16Array([0,1,2,3,4,5,6,7,8]);
indBuf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
debug('Draw a filled square using a triangle fan with a vertex buffer offset and verify that it fills the entire canvas.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_FAN, 3, vertices.length / 2 - 3);
checkTriFan(gl, w);
debug('Draw a filled square using an indexed triangle fan with an index buffer offset and verify that it fills the entire canvas.');
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLE_FAN, indices.length - 3, gl.UNSIGNED_SHORT, 3 * 2);
checkTriFan(gl, w);
}
</script>
</head>
<body>
<canvas id="testbed" width="10px" height="10px" style="width:50px; height:50px"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
description('Verify that LINE_LOOP and TRIANGLE_FAN works correctly.');
runTest();
successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>

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

@ -223,7 +223,10 @@ var runFeatureTest = function(params) {
var wtu = WebGLTestUtils;
var gridRes = params.gridRes;
var tolerance = params.tolerance || 0;
var vertexTolerance = params.tolerance || 0;
var fragmentTolerance = vertexTolerance;
if ('fragmentTolerance' in params)
fragmentTolerance = params.fragmentTolerance || 0;
description("Testing GLSL feature: " + params.feature);
@ -252,13 +255,15 @@ var runFeatureTest = function(params) {
input: "color",
output: "vColor",
vertexShaderTemplate: vertexShaderTemplate,
fragmentShaderTemplate: baseFragmentShader
fragmentShaderTemplate: baseFragmentShader,
tolerance: vertexTolerance
},
{ type: "fragment",
input: "vColor",
output: "gl_FragColor",
vertexShaderTemplate: baseVertexShader,
fragmentShaderTemplate: fragmentShaderTemplate
fragmentShaderTemplate: fragmentShaderTemplate,
tolerance: fragmentTolerance
}
];
for (var ss = 0; ss < shaderInfos.length; ++ss) {
@ -328,7 +333,7 @@ var runFeatureTest = function(params) {
}
var testImg = makeImage(canvas);
reportResults(refData, refImg, testData, testImg);
reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance);
}
}
@ -364,7 +369,7 @@ var runFeatureTest = function(params) {
console.appendChild(div);
}
function reportResults(refData, refImage, testData, testImage) {
function reportResults(refData, refImage, testData, testImage, tolerance) {
var same = true;
for (var yy = 0; yy < height; ++yy) {
for (var xx = 0; xx < width; ++xx) {
@ -487,6 +492,18 @@ return {
* tests:
* The code for each test. It is assumed the tests are for
* float, vec2, vec3, vec4 in that order.
*
* tolerance: (optional)
* Allow some tolerance in the comparisons. The tolerance is applied to
* both vertex and fragment shaders. The default tolerance is 0, meaning
* the values have to be identical.
*
* fragmentTolerance: (optional)
* Specify a tolerance which only applies to fragment shaders. The
* fragment-only tolerance will override the shared tolerance for
* fragment shaders if both are specified. Fragment shaders usually
* use mediump float precision so they sometimes require higher tolerance
* than vertex shaders which use highp.
*/
runFeatureTest: runFeatureTest,

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

@ -130,18 +130,33 @@ function shouldGenerateGLError(ctx, glErrors, evalStr) {
/**
* Tests that the first error GL returns is the specified error.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} glError The expected gl error.
* @param {number|!Array.<number>} glError The expected gl
* error. Multiple errors can be passed in using an
* array.
* @param {string} opt_msg Optional additional message.
*/
function glErrorShouldBe(gl, glError, opt_msg) {
function glErrorShouldBe(gl, glErrors, opt_msg) {
if (!glErrors.length) {
glErrors = [glErrors];
}
opt_msg = opt_msg || "";
var err = gl.getError();
if (err != glError) {
testFailed("getError expected: " + getGLErrorAsString(gl, glError) +
". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
var ndx = glErrors.indexOf(err);
if (ndx < 0) {
if (glErrors.length == 1) {
testFailed("getError expected: " + getGLErrorAsString(gl, glErrors[0]) +
". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
} else {
var errs = [];
for (var ii = 0; ii < glErrors.length; ++ii) {
errs.push(getGLErrorAsString(gl, glErrors[ii]));
}
testFailed("getError expected one of: [" + errs.join(", ") +
"]. Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
}
} else {
testPassed("getError was expected value: " +
getGLErrorAsString(gl, glError) + " : " + opt_msg);
getGLErrorAsString(gl, err) + " : " + opt_msg);
}
};
@ -361,18 +376,18 @@ var getBasePathForResources = function() {
function loadStandardVertexShader(context) {
return loadShader(
context,
getBasePathForResources() + "vertexShader.vert",
context.VERTEX_SHADER,
true);
context,
getBasePathForResources() + "vertexShader.vert",
context.VERTEX_SHADER,
true);
}
function loadStandardFragmentShader(context) {
return loadShader(
context,
getBasePathForResources() + "fragmentShader.frag",
context.FRAGMENT_SHADER,
true);
context,
getBasePathForResources() + "fragmentShader.frag",
context.FRAGMENT_SHADER,
true);
}
//

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

@ -61,8 +61,8 @@ else {
debug("");
debug("Check default values");
shouldBe('context.getParameter(context.ACTIVE_TEXTURE)', 'context.TEXTURE0');
shouldBe('(context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[0] == 1) || (context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[1] == 1)', 'true');
shouldBe('(context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[0] == 1) || (context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[1] == 1)', 'true');
shouldBe('(context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[0] <= 1) && (context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[0] > 0) && (context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[1] >= 1)', 'true');
shouldBe('(context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[0] <= 1) && (context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[0] > 0) && (context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[1] >= 1)', 'true');
shouldBe('context.getParameter(context.ARRAY_BUFFER_BINDING)', 'null');
shouldBe('context.getParameter(context.BLEND)', 'false');
shouldBe('context.getParameter(context.BLEND_COLOR)', '[0, 0, 0, 0]');

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

@ -22,6 +22,7 @@ description("Test texImage2D conversions.");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("example");
var gl = wtu.create3DContext(canvas);
gl.disable(gl.DITHER);
var program = wtu.setupTexturedQuad(gl);
glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");

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

@ -46,6 +46,7 @@ function init()
var canvas = document.getElementById("example");
gl = wtu.create3DContext(canvas);
gl.disable(gl.DITHER);
var program = wtu.setupTexturedQuad(gl);
gl.clearColor(0,0,0,1);

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

@ -35,6 +35,7 @@ description('Tests texSubImage2D upload path from Uint8Array');
var wtu = WebGLTestUtils;
var canvas = document.getElementById("example");
var gl = wtu.create3DContext(canvas);
gl.disable(gl.DITHER);
var program = wtu.setupProgram(
gl,
[wtu.setupSimpleTextureVertexShader(gl),

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

@ -211,12 +211,17 @@ function checkRect(x, y, width, height, color) {
function fillLevel(target, level, size, color) {
var numPixels = size * size;
var pixels = new Uint8Array(numPixels * 4);
for (var jj = 0; jj < numPixels; ++jj) {
var pixelRow = new Uint8Array(size * 4);
for (var jj = 0; jj < size; ++jj) {
var off = jj * 4;
pixels[off + 0] = color[0];
pixels[off + 1] = color[1];
pixels[off + 2] = color[2];
pixels[off + 3] = color[3];
pixelRow[off + 0] = color[0];
pixelRow[off + 1] = color[1];
pixelRow[off + 2] = color[2];
pixelRow[off + 3] = color[3];
}
for (var jj = 0; jj < size; ++jj) {
var off = jj * size * 4;
pixels.set(pixelRow, off);
}
gl.texImage2D(
target, level, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE,

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

@ -14,7 +14,7 @@ found in the LICENSE file.
<script src="../resources/webgl-test-utils.js"></script>
</head>
<body>
<canvas id="example" width="256" height="256" style="width: 40px; height: 40px;"></canvas>
<canvas id="example" width="32" height="32" style="width: 40px; height: 40px;"></canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
@ -149,14 +149,29 @@ function checkTexture(width, height, cubeMap) {
function fillLevel(level, width, height, color, opt_cubemap) {
var numPixels = width * height;
var pixels = new Uint8Array(numPixels * 4);
for (var jj = 0; jj < numPixels; ++jj) {
var pixels = null;
var largeDim = Math.max(width, height);
var smallDim = Math.min(width, height);
var pixelRow = new Uint8Array(largeDim * 4);
for (var jj = 0; jj < largeDim; ++jj) {
var off = jj * 4;
pixels[off + 0] = color[0];
pixels[off + 1] = color[1];
pixels[off + 2] = color[2];
pixels[off + 3] = color[3];
pixelRow[off + 0] = color[0];
pixelRow[off + 1] = color[1];
pixelRow[off + 2] = color[2];
pixelRow[off + 3] = color[3];
}
if (largeDim == numPixels) {
pixels = pixelRow;
} else {
var pixels = new Uint8Array(numPixels * 4);
for (var jj = 0; jj < smallDim; ++jj) {
var off = jj * largeDim * 4;
pixels.set(pixelRow, off);
}
}
var targets = opt_cubemap ? [
gl.TEXTURE_CUBE_MAP_POSITIVE_X,
gl.TEXTURE_CUBE_MAP_NEGATIVE_X,

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

@ -519,18 +519,14 @@ function testConstructionWithOutOfRangeValues(type, name) {
}, "Construction of " + name + " with out-of-range offset");
}
function testConstructionWithNegativeOutOfRangeValues(type, name) {
try {
var buffer = new ArrayBuffer(-1);
testFailed("Construction of ArrayBuffer with negative size should throw exception");
} catch (e) {
testPassed("Construction of ArrayBuffer with negative size threw exception");
}
try {
var array = new type(-1);
testFailed("Construction of " + name + " with negative size should throw exception");
} catch (e) {
testPassed("Construction of " + name + " with negative size threw exception");
function testConstructionWithNegativeOutOfRangeValues(type, name, elementSizeInBytes) {
if (elementSizeInBytes > 1) {
try {
var array = new type(-1);
testFailed("Construction of " + name + " with negative size should throw exception");
} catch (e) {
testPassed("Construction of " + name + " with negative size threw exception");
}
}
shouldThrowIndexSizeErr(function() {
var buffer = new ArrayBuffer(4);
@ -895,7 +891,7 @@ function runTests() {
testCase.expectedValues);
testConstructionWithNullBuffer(type, name);
testConstructionWithOutOfRangeValues(type, name);
testConstructionWithNegativeOutOfRangeValues(type, name);
testConstructionWithNegativeOutOfRangeValues(type, name, testCase.elementSizeInBytes);
testConstructionWithUnalignedOffset(type, name, testCase.elementSizeInBytes);
testConstructionWithUnalignedLength(type, name, testCase.elementSizeInBytes);
testConstructionOfHugeArray(type, name, testCase.elementSizeInBytes);

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

@ -95,6 +95,15 @@ locationArray0 = contextA.getUniformLocation(programS, "u_array[0]");
shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.uniform1i(locationSx, 3)");
shouldBe("contextA.getUniform(programS, locationSx)", "3");
// getUniformLocation should return a different object everytime, should not cache and return the same object
debug("Testing that getUniformLocation returns a different object everytime");
locationSx = contextA.getUniformLocation(programS, "u_struct.x");
locationSx2 = contextA.getUniformLocation(programS, "u_struct.x");
shouldBeFalse("locationSx === locationSx2");
locationSx.foo = {};
locationSx2.foo = {};
shouldBeFalse("locationSx.foo === locationSx2.foo");
successfullyParsed = true;
</script>

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

@ -1,22 +0,0 @@
# HG changeset patch
# Parent 587913950733649a7cbd184a195b08cbb86b2fed
diff --git a/content/canvas/test/webgl/conformance/more/00_test_list.txt b/content/canvas/test/webgl/conformance/more/00_test_list.txt
--- a/content/canvas/test/webgl/conformance/more/00_test_list.txt
+++ b/content/canvas/test/webgl/conformance/more/00_test_list.txt
@@ -1,12 +1,15 @@
conformance/constants.html
conformance/getContext.html
conformance/methods.html
-conformance/quickCheckAPI.html
+#this test causes whichever comes after to intermittently time out.
+#forcing a GC run doesn't solve this issue. Could be something about using a random amount of memory that
+#can be too high, causing e.g. swapping.
+#conformance/quickCheckAPI.html
conformance/webGLArrays.html
functions/bindBuffer.html
functions/bindBufferBadArgs.html
functions/bindFramebufferLeaveNonZero.html
functions/bufferData.html
functions/bufferDataBadArgs.html
functions/bufferSubData.html
functions/bufferSubDataBadArgs.html

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

@ -1,6 +1,5 @@
# HG changeset patch
# Parent 95e5d92098ad52788348e609e261305d4b05b551
# Parent 9c1a90f789e3d43455cb18a9a911627c80c0d9ac
diff --git a/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html b/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html
--- a/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html
+++ b/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html

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

@ -1,3 +1,4 @@
conformance/context/context-lost-restored.html
conformance/context/premultiplyalpha-test.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
@ -11,3 +12,4 @@ conformance/more/functions/uniformfArrayLen1.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/renderbuffers/framebuffer-object-attachment.html
conformance/misc/object-deletion-behaviour.html

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

@ -1,3 +1,4 @@
conformance/context/context-lost-restored.html
conformance/context/premultiplyalpha-test.html
conformance/glsl/misc/glsl-function-nodes.html
conformance/glsl/misc/glsl-long-variable-names.html
@ -9,3 +10,4 @@ conformance/more/functions/uniformiBadArgs.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/renderbuffers/framebuffer-object-attachment.html
conformance/misc/object-deletion-behaviour.html

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

@ -1,7 +1,7 @@
conformance/context/context-lost-restored.html
conformance/context/premultiplyalpha-test.html
conformance/glsl/functions/glsl-function-atan.html
conformance/glsl/functions/glsl-function-atan-xy.html
conformance/glsl/functions/glsl-function-mod-gentype.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
conformance/glsl/misc/shader-with-long-line.html
@ -11,3 +11,4 @@ conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/struct-nesting-under-maximum.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/renderbuffers/framebuffer-object-attachment.html
conformance/misc/object-deletion-behaviour.html

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

@ -1,16 +1,9 @@
# HG changeset patch
# Parent 2dbd71999fe8a8da476ab6cc97716f7b7c294fb8
# User Doug Sherk <dsherk@mozilla.com>
Bug 693703: added additional logging information for mochitests, incl. image reference differences r=bjacob
Added some code to print to dump output of WebGL mochitest failures. Also added
special code to handle incorrect reference images. It will now provide the user
with a way to compare the reference and actual drawings.
# Parent 4ed0bad4933ba69927ee5f75cf67093d3e99566a
diff --git a/content/canvas/test/webgl/conformance/glsl/misc/glsl-function-nodes.html b/content/canvas/test/webgl/conformance/glsl/misc/glsl-function-nodes.html
--- a/content/canvas/test/webgl/conformance/glsl/misc/glsl-function-nodes.html
+++ b/content/canvas/test/webgl/conformance/glsl/misc/glsl-function-nodes.html
@@ -115,17 +115,18 @@ function init()
@@ -117,17 +117,18 @@ function init()
var bufFunction = new Uint8Array(width * height * 4);
var bufMacro = new Uint8Array(width * height * 4);
@ -148,7 +141,7 @@ diff --git a/content/canvas/test/webgl/resources/js-test-pre.js b/content/canvas
+
+ testFailed(msg);
+
+ var data = 'REFTEST TEST-UNEXPECTED-FAIL | ' + msg + ' | image comparison (==)\n' +
+ var data = 'REFTEST TEST-DEBUG-INFO | ' + msg + ' | image comparison (==)\n' +
+ 'REFTEST IMAGE 1 (TEST): ' + testData + '\n' +
+ 'REFTEST IMAGE 2 (REFERENCE): ' + refData;
+ dump('FAIL: ' + data + '\n');

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

@ -1,6 +1,5 @@
# HG changeset patch
# Parent 041265c6ac29c43856a8df4d4581cb6a04b95a68
# Parent bf9d7872738cdb7cf425e6dd060ae62882487e1a
diff --git a/content/canvas/test/webgl/conformance/extensions/oes-standard-derivatives.html b/content/canvas/test/webgl/conformance/extensions/oes-standard-derivatives.html
--- a/content/canvas/test/webgl/conformance/extensions/oes-standard-derivatives.html
+++ b/content/canvas/test/webgl/conformance/extensions/oes-standard-derivatives.html

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

@ -1,5 +1,6 @@
# HG changeset patch
# Parent 0e44920c4e5e697f86e0a42b909c5a032d70a1a4
# Parent 41137626edf2a358f2be1b7ed3f83211230ab4f5
diff --git a/content/canvas/test/webgl/resources/webgl-test-harness.js b/content/canvas/test/webgl/resources/webgl-test-harness.js
--- a/content/canvas/test/webgl/resources/webgl-test-harness.js
+++ b/content/canvas/test/webgl/resources/webgl-test-harness.js

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

@ -83,6 +83,10 @@ DIRS += \
workers \
$(NULL)
ifdef MOZ_B2G_RIL #{
DIRS += telephony
endif #}
ifdef ENABLE_TESTS
DIRS += tests
ifneq (,$(filter gtk2 cocoa windows android qt os2,$(MOZ_WIDGET_TOOLKIT)))

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

@ -1641,6 +1641,7 @@ jsid nsDOMClassInfo::sURL_id = JSID_VOID;
jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID;
jsid nsDOMClassInfo::sAutoIncrement_id = JSID_VOID;
jsid nsDOMClassInfo::sUnique_id = JSID_VOID;
jsid nsDOMClassInfo::sMultiEntry_id = JSID_VOID;
jsid nsDOMClassInfo::sOnload_id = JSID_VOID;
jsid nsDOMClassInfo::sOnerror_id = JSID_VOID;
@ -1904,6 +1905,7 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
SET_JSID_TO_STRING(sKeyPath_id, cx, "keyPath");
SET_JSID_TO_STRING(sAutoIncrement_id, cx, "autoIncrement");
SET_JSID_TO_STRING(sUnique_id, cx, "unique");
SET_JSID_TO_STRING(sMultiEntry_id, cx, "multiEntry");
SET_JSID_TO_STRING(sOnload_id, cx, "onload");
SET_JSID_TO_STRING(sOnerror_id, cx, "onerror");
@ -4902,6 +4904,7 @@ nsDOMClassInfo::ShutDown()
sKeyPath_id = JSID_VOID;
sAutoIncrement_id = JSID_VOID;
sUnique_id = JSID_VOID;
sMultiEntry_id = JSID_VOID;
sOnload_id = JSID_VOID;
sOnerror_id = JSID_VOID;

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

@ -295,6 +295,7 @@ public:
static jsid sKeyPath_id;
static jsid sAutoIncrement_id;
static jsid sUnique_id;
static jsid sMultiEntry_id;
static jsid sOnload_id;
static jsid sOnerror_id;

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

@ -7,6 +7,7 @@ DOM_SRCDIRS = \
dom/src/offline \
dom/src/geolocation \
dom/src/notification \
dom/telephony \
dom/workers \
content/xbl/src \
content/xul/document/src \

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

@ -97,7 +97,8 @@ DatabaseInfo::~DatabaseInfo()
IndexInfo::IndexInfo()
: id(LL_MININT),
unique(false),
autoIncrement(false)
autoIncrement(false),
multiEntry(false)
{
MOZ_COUNT_CTOR(IndexInfo);
}
@ -107,7 +108,8 @@ IndexInfo::IndexInfo(const IndexInfo& aOther)
name(aOther.name),
keyPath(aOther.keyPath),
unique(aOther.unique),
autoIncrement(aOther.autoIncrement)
autoIncrement(aOther.autoIncrement),
multiEntry(aOther.multiEntry)
{
MOZ_COUNT_CTOR(IndexInfo);
}

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

@ -121,6 +121,7 @@ struct IndexInfo
nsString keyPath;
bool unique;
bool autoIncrement;
bool multiEntry;
};
struct ObjectStoreInfo
@ -149,7 +150,8 @@ struct IndexUpdateInfo
~IndexUpdateInfo();
#endif
IndexInfo info;
PRInt64 indexId;
bool indexUnique;
Key value;
};

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

@ -387,11 +387,8 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
DatabaseInfo* databaseInfo = Info();
if (databaseInfo->ContainsStoreName(aName)) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
}
nsString keyPath;
keyPath.SetIsVoid(true);
bool autoIncrement = false;
if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
@ -437,8 +434,17 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
autoIncrement = !!boolVal;
}
if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
return NS_ERROR_DOM_SYNTAX_ERR;
if (databaseInfo->ContainsStoreName(aName)) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
}
if (!keyPath.IsVoid()) {
if (keyPath.IsEmpty() && autoIncrement) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
}
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
@ -498,6 +504,9 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
info->RemoveObjectStore(aName);
transaction->ReleaseCachedObjectStore(aName);
return NS_OK;
}
@ -723,8 +732,8 @@ CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
"INSERT INTO object_store (id, name, key_path, auto_increment) "
"VALUES (:id, :name, :key_path, :auto_increment)"
"INSERT INTO object_store (id, auto_increment, name, key_path) "
"VALUES (:id, :auto_increment, :name, :key_path)"
));
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -734,15 +743,17 @@ CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
mObjectStore->IsAutoIncrement() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
mObjectStore->KeyPath());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
mObjectStore->IsAutoIncrement() ? 1 : 0);
rv = mObjectStore->HasKeyPath() ?
stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
mObjectStore->KeyPath()) :
stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->Execute();

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

@ -247,8 +247,18 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
info->id = stmt->AsInt64(1);
rv = stmt->GetString(2, info->keyPath);
PRInt32 columnType;
nsresult rv = stmt->GetTypeOfIndex(2, &columnType);
NS_ENSURE_SUCCESS(rv, rv);
if (columnType == mozIStorageStatement::VALUE_TYPE_NULL) {
info->keyPath.SetIsVoid(true);
}
else {
NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Should be a string");
rv = stmt->GetString(2, info->keyPath);
NS_ENSURE_SUCCESS(rv, rv);
}
info->autoIncrement = !!stmt->AsInt32(3);
info->databaseId = aDatabaseId;
@ -263,7 +273,7 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
// Load index information
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT object_store_id, id, name, key_path, unique_index, "
"SELECT object_store_id, id, name, key_path, unique_index, multientry, "
"object_store_autoincrement "
"FROM object_store_index"
), getter_AddRefs(stmt));
@ -297,7 +307,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
NS_ENSURE_SUCCESS(rv, rv);
indexInfo->unique = !!stmt->AsInt32(4);
indexInfo->autoIncrement = !!stmt->AsInt32(5);
indexInfo->multiEntry = !!stmt->AsInt32(5);
indexInfo->autoIncrement = !!stmt->AsInt32(6);
}
NS_ENSURE_SUCCESS(rv, rv);

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

@ -318,6 +318,7 @@ IDBIndex::Create(IDBObjectStore* aObjectStore,
index->mName = aIndexInfo->name;
index->mKeyPath = aIndexInfo->keyPath;
index->mUnique = aIndexInfo->unique;
index->mMultiEntry = aIndexInfo->multiEntry;
index->mAutoIncrement = aIndexInfo->autoIncrement;
return index.forget();
@ -396,6 +397,15 @@ IDBIndex::GetUnique(bool* aUnique)
return NS_OK;
}
NS_IMETHODIMP
IDBIndex::GetMultiEntry(bool* aMultiEntry)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
*aMultiEntry = mMultiEntry;
return NS_OK;
}
NS_IMETHODIMP
IDBIndex::GetObjectStore(nsIIDBObjectStore** aObjectStore)
{

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

@ -87,6 +87,11 @@ public:
return mUnique;
}
bool IsMultiEntry() const
{
return mMultiEntry;
}
bool IsAutoIncrement() const
{
return mAutoIncrement;
@ -110,6 +115,7 @@ private:
nsString mName;
nsString mKeyPath;
bool mUnique;
bool mMultiEntry;
bool mAutoIncrement;
};

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

@ -97,9 +97,6 @@ public:
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
nsresult UpdateIndexes(mozIStorageConnection* aConnection,
PRInt64 aObjectDataId);
private:
// In-params.
nsRefPtr<IDBObjectStore> mObjectStore;
@ -422,15 +419,13 @@ typedef nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> KeyPathTokenizer;
inline
nsresult
GetKeyFromValue(JSContext* aCx,
jsval aVal,
const nsAString& aKeyPath,
Key& aKey)
GetJSValFromKeyPath(JSContext* aCx,
jsval aVal,
const nsAString& aKeyPath,
jsval& aKey)
{
NS_ASSERTION(aCx, "Null pointer!");
// aVal can be primitive iff the key path is empty.
NS_ASSERTION(!JSVAL_IS_PRIMITIVE(aVal) || aKeyPath.IsEmpty(),
"Why are we here!?");
NS_ASSERTION(IDBObjectStore::IsValidKeyPath(aCx, aKeyPath),
"This will explode!");
@ -438,25 +433,39 @@ GetKeyFromValue(JSContext* aCx,
jsval intermediate = aVal;
while (tokenizer.hasMoreTokens()) {
nsString token(tokenizer.nextToken());
const nsDependentSubstring& token = tokenizer.nextToken();
if (!token.Length()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
const jschar* keyPathChars = token.get();
const jschar* keyPathChars = token.BeginReading();
const size_t keyPathLen = token.Length();
if (JSVAL_IS_PRIMITIVE(intermediate)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
intermediate = JSVAL_VOID;
break;
}
JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(intermediate),
keyPathChars, keyPathLen, &intermediate);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
aKey = intermediate;
return NS_OK;
}
if (NS_FAILED(aKey.SetFromJSVal(aCx, intermediate))) {
inline
nsresult
GetKeyFromValue(JSContext* aCx,
jsval aVal,
const nsAString& aKeyPath,
Key& aKey)
{
jsval key;
nsresult rv = GetJSValFromKeyPath(aCx, aVal, aKeyPath, key);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(aKey.SetFromJSVal(aCx, key))) {
aKey.Unset();
}
@ -574,82 +583,63 @@ IDBObjectStore::IsValidKeyPath(JSContext* aCx,
// static
nsresult
IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
PRUint32 aDataLength,
const nsAString& aKeyPath,
JSContext* aCx,
Key& aValue)
IDBObjectStore::AppendIndexUpdateInfo(PRInt64 aIndexID,
const nsAString& aKeyPath,
bool aUnique,
bool aMultiEntry,
JSContext* aCx,
jsval aObject,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
{
NS_ASSERTION(aData, "Null pointer!");
NS_ASSERTION(aDataLength, "Empty data!");
NS_ASSERTION(aCx, "Null pointer!");
JSAutoRequest ar(aCx);
jsval clone;
if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
aDataLength, JS_STRUCTURED_CLONE_VERSION,
&clone, NULL, NULL)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
if (JSVAL_IS_PRIMITIVE(clone) && !aKeyPath.IsEmpty()) {
// This isn't an object, so just leave the key unset.
aValue.Unset();
return NS_OK;
}
nsresult rv = GetKeyFromValue(aCx, clone, aKeyPath, aValue);
jsval key;
nsresult rv = GetJSValFromKeyPath(aCx, aObject, aKeyPath, key);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/* static */
nsresult
IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
JSContext* aCx,
jsval aObject,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
{
JSObject* cloneObj = nsnull;
PRUint32 count = aObjectStoreInfo->indexes.Length();
if (count) {
if (!aUpdateInfoArray.SetCapacity(count)) {
NS_ERROR("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
if (aMultiEntry && !JSVAL_IS_PRIMITIVE(key) &&
JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(key))) {
JSObject* array = JSVAL_TO_OBJECT(key);
jsuint arrayLength;
if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
const IndexInfo& indexInfo = aObjectStoreInfo->indexes[indexesIndex];
if (JSVAL_IS_PRIMITIVE(aObject) && !indexInfo.keyPath.IsEmpty()) {
continue;
for (jsuint arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
jsval arrayItem;
if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
Key value;
nsresult rv = GetKeyFromValue(aCx, aObject, indexInfo.keyPath, value);
NS_ENSURE_SUCCESS(rv, rv);
if (value.IsUnset()) {
if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
continue;
}
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
updateInfo->info = indexInfo;
updateInfo->indexId = aIndexID;
updateInfo->indexUnique = aUnique;
updateInfo->value = value;
}
}
else {
aUpdateInfoArray.Clear();
Key value;
if (NS_FAILED(value.SetFromJSVal(aCx, key)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
return NS_OK;
}
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
updateInfo->indexId = aIndexID;
updateInfo->indexUnique = aUnique;
updateInfo->value = value;
}
return NS_OK;
}
/* static */
// static
nsresult
IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
PRInt64 aObjectStoreId,
@ -659,21 +649,13 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
PRInt64 aObjectDataId,
const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
{
#ifdef DEBUG
if (aAutoIncrement) {
NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!");
}
else {
NS_ASSERTION(aObjectDataId == LL_MININT, "Bad objectData id!");
}
#endif
PRUint32 indexCount = aUpdateInfoArray.Length();
NS_ASSERTION(!aAutoIncrement || aObjectDataId != LL_MININT,
"Bad objectData id!");
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv;
if (!aAutoIncrement) {
if (aObjectDataId == LL_MININT) {
stmt = aTransaction->GetCachedStatement(
"SELECT id "
"FROM object_data "
@ -735,25 +717,24 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
NS_ENSURE_SUCCESS(rv, rv);
}
for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
const IndexUpdateInfo& updateInfo = aUpdateInfoArray[indexIndex];
NS_ASSERTION(updateInfo.info.autoIncrement == aAutoIncrement, "Huh?!");
PRUint32 infoCount = aUpdateInfoArray.Length();
for (PRUint32 i = 0; i < infoCount; i++) {
const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i];
// Insert new values.
stmt = aTransaction->IndexDataInsertStatement(aAutoIncrement,
updateInfo.info.unique);
updateInfo.indexUnique);
NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
mozStorageStatementScoper scoper4(stmt);
rv = stmt->BindInt64ByName(indexId, updateInfo.info.id);
rv = stmt->BindInt64ByName(indexId, updateInfo.indexId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
NS_ENSURE_SUCCESS(rv, rv);
if (!updateInfo.info.autoIncrement) {
if (!aAutoIncrement) {
rv = aObjectStoreKey.BindToStatement(stmt, objectDataKey);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -762,6 +743,23 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) {
// If we're inserting multiple entries for the same unique index, then
// we might have failed to insert due to colliding with another entry for
// the same index in which case we should ignore it.
for (PRInt32 j = (PRInt32)i - 1;
j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId;
--j) {
if (updateInfo.value == aUpdateInfoArray[j].value) {
// We found a key with the same value for the same index. So we
// must have had a collision with a value we just inserted.
rv = NS_OK;
break;
}
}
}
if (NS_FAILED(rv)) {
return rv;
}
@ -906,24 +904,20 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
// Return DATA_ERR if a key was passed in and this objectStore uses inline
// keys.
if (!JSVAL_IS_VOID(aKeyVal) && !mKeyPath.IsEmpty()) {
if (!JSVAL_IS_VOID(aKeyVal) && HasKeyPath()) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
JSAutoRequest ar(aCx);
if (mKeyPath.IsEmpty()) {
if (!HasKeyPath()) {
// Out-of-line keys must be passed in.
rv = aKey.SetFromJSVal(aCx, aKeyVal);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
else if (!mAutoIncrement) {
// Inline keys live on the object. Make sure that the value passed in is an
// object.
if (JSVAL_IS_PRIMITIVE(aValue)) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
rv = GetKeyFromValue(aCx, aValue, mKeyPath, aKey);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -940,28 +934,116 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
NS_ERROR("This should never fail!");
}
rv = GetIndexUpdateInfo(info, aCx, aValue, aUpdateInfoArray);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PRUint32 count = info->indexes.Length();
aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
const IndexInfo& indexInfo = info->indexes[indexesIndex];
const jschar* keyPathChars =
reinterpret_cast<const jschar*>(mKeyPath.get());
const size_t keyPathLen = mKeyPath.Length();
JSBool ok = JS_FALSE;
rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
indexInfo.unique, indexInfo.multiEntry,
aCx, aValue, aUpdateInfoArray);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!mKeyPath.IsEmpty() && aKey.IsUnset()) {
NS_ASSERTION(mAutoIncrement, "Should have bailed earlier!");
nsString targetObjectPropName;
JSObject* targetObject = nsnull;
JSObject* obj = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = NS_OK;
if (mAutoIncrement && HasKeyPath()) {
NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!");
jsval key = OBJECT_TO_JSVAL(obj);
ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
keyPathLen, key, nsnull, nsnull,
JSPROP_ENUMERATE);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (JSVAL_IS_PRIMITIVE(aValue)) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
// From this point on we have to try to remove the property.
KeyPathTokenizer tokenizer(mKeyPath, '.');
NS_ASSERTION(tokenizer.hasMoreTokens(),
"Shouldn't have empty keypath and autoincrement");
JSObject* obj = JSVAL_TO_OBJECT(aValue);
while (tokenizer.hasMoreTokens()) {
const nsDependentSubstring& token = tokenizer.nextToken();
NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
const jschar* keyPathChars = token.BeginReading();
const size_t keyPathLen = token.Length();
JSBool hasProp;
if (!targetObject) {
// We're still walking the chain of existing objects
JSBool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
&hasProp);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (hasProp) {
// Get if the property exists...
jsval intermediate;
JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen,
&intermediate);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (tokenizer.hasMoreTokens()) {
// ...and walk to it if there are more steps...
if (JSVAL_IS_PRIMITIVE(intermediate)) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
obj = JSVAL_TO_OBJECT(intermediate);
}
else {
// ...otherwise use it as key
aKey.SetFromJSVal(aCx, intermediate);
if (aKey.IsUnset()) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
}
}
else {
// If the property doesn't exist, fall into below path of starting
// to define properties
targetObject = obj;
targetObjectPropName = token;
}
}
if (targetObject) {
// We have started inserting new objects or are about to just insert
// the first one.
if (tokenizer.hasMoreTokens()) {
// If we're not at the end, we need to add a dummy object to the chain.
JSObject* dummy = JS_NewObject(aCx, nsnull, nsnull, nsnull);
if (!dummy) {
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
break;
}
if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
token.Length(),
OBJECT_TO_JSVAL(dummy), nsnull, nsnull,
JSPROP_ENUMERATE)) {
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
break;
}
obj = dummy;
}
else {
JSObject* dummy = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
if (!dummy) {
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
break;
}
if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
token.Length(), OBJECT_TO_JSVAL(dummy),
nsnull, nsnull, JSPROP_ENUMERATE)) {
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
break;
}
}
}
}
}
JSStructuredCloneCallbacks callbacks = {
@ -979,13 +1061,15 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
rv = NS_ERROR_DOM_DATA_CLONE_ERR;
}
if (ok) {
if (targetObject) {
// If this fails, we lose, and the web page sees a magical property
// appear on the object :-(
jsval succeeded;
ok = JS_DeleteUCProperty2(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
keyPathLen, &succeeded);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!JS_DeleteUCProperty2(aCx, targetObject,
targetObjectPropName.get(),
targetObjectPropName.Length(), &succeeded)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
NS_ASSERTION(JSVAL_IS_BOOLEAN(succeeded), "Wtf?");
NS_ENSURE_TRUE(JSVAL_TO_BOOLEAN(succeeded),
NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1372,6 +1456,7 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
bool unique = false;
bool multiEntry = false;
// Get optional arguments.
if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
@ -1395,6 +1480,17 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
unique = !!boolVal;
if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sMultiEntry_id, &val)) {
NS_WARNING("JS_GetPropertyById failed!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
NS_WARNING("JS_ValueToBoolean failed!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
multiEntry = !!boolVal;
}
DatabaseInfo* databaseInfo = mTransaction->Database()->Info();
@ -1409,6 +1505,7 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
indexInfo->name = aName;
indexInfo->keyPath = aKeyPath;
indexInfo->unique = unique;
indexInfo->multiEntry = multiEntry;
indexInfo->autoIncrement = mAutoIncrement;
// Don't leave this in the list if we fail below!
@ -1530,6 +1627,14 @@ IDBObjectStore::DeleteIndex(const nsAString& aName)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
info->indexes.RemoveElementAt(index);
for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
if (mCreatedIndexes[i]->Name() == aName) {
mCreatedIndexes.RemoveElementAt(i);
break;
}
}
return NS_OK;
}
@ -2160,8 +2265,9 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(
"INSERT INTO object_store_index (id, name, key_path, unique_index, "
"object_store_id, object_store_autoincrement) "
"VALUES (:id, :name, :key_path, :unique, :osid, :os_auto_increment)"
"multientry, object_store_id, object_store_autoincrement) "
"VALUES (:id, :name, :key_path, :unique, :multientry, :osid, "
":os_auto_increment)"
);
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -2182,6 +2288,10 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mIndex->IsUnique() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
mIndex->IsMultiEntry() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mIndex->ObjectStore()->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -2238,69 +2348,69 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
mIndex->ObjectStore()->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
bool hasResult;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
nsCOMPtr<mozIStorageStatement> insertStmt =
mTransaction->IndexDataInsertStatement(mIndex->IsAutoIncrement(),
mIndex->IsUnique());
NS_ENSURE_TRUE(insertStmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!hasResult) {
// Bail early if we have no data to avoid creating the below runtime
return NS_OK;
}
mozStorageStatementScoper scoper2(insertStmt);
ThreadLocalJSRuntime* tlsEntry =
reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!tlsEntry) {
tlsEntry = ThreadLocalJSRuntime::Create();
NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"),
stmt->AsInt64(0));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PR_SetThreadPrivate(sTLSIndex, tlsEntry);
}
if (!mIndex->IsAutoIncrement()) {
NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
Key key;
rv = key.SetFromStatement(stmt, 2);
NS_ENSURE_SUCCESS(rv, rv);
rv =
key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("object_data_key"));
NS_ENSURE_SUCCESS(rv, rv);
}
JSContext* cx = tlsEntry->Context();
JSAutoRequest ar(cx);
do {
const PRUint8* data;
PRUint32 dataLength;
rv = stmt->GetSharedBlob(1, &dataLength, &data);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
ThreadLocalJSRuntime* tlsEntry =
reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
if (!tlsEntry) {
tlsEntry = ThreadLocalJSRuntime::Create();
NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PR_SetThreadPrivate(sTLSIndex, tlsEntry);
jsval clone;
if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(data),
dataLength, JS_STRUCTURED_CLONE_VERSION,
&clone, NULL, NULL)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
nsTArray<IndexUpdateInfo> updateInfo;
rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
mIndex->KeyPath(),
mIndex->IsUnique(),
mIndex->IsMultiEntry(),
tlsEntry->Context(),
clone, updateInfo);
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 objectDataID = stmt->AsInt64(0);
Key key;
rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
mIndex->KeyPath(),
tlsEntry->Context(),
key);
NS_ENSURE_SUCCESS(rv, rv);
if (key.IsUnset()) {
continue;
if (!mIndex->IsAutoIncrement()) {
rv = key.SetFromStatement(stmt, 2);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
key.SetFromInteger(objectDataID);
}
rv = key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("value"));
rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
key, mIndex->IsAutoIncrement(),
false, objectDataID, updateInfo);
NS_ENSURE_SUCCESS(rv, rv);
rv = insertStmt->Execute();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
} while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return NS_OK;
}

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

@ -76,17 +76,13 @@ public:
IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
static nsresult
GetKeyPathValueFromStructuredData(const PRUint8* aData,
PRUint32 aDataLength,
const nsAString& aKeyPath,
JSContext* aCx,
Key& aValue);
static nsresult
GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
JSContext* aCx,
jsval aObject,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
AppendIndexUpdateInfo(PRInt64 aIndexID,
const nsAString& aKeyPath,
bool aUnique,
bool aMultiEntry,
JSContext* aCx,
jsval aObject,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
static nsresult
UpdateIndexes(IDBTransaction* aTransaction,
@ -145,6 +141,11 @@ public:
return mKeyPath;
}
const bool HasKeyPath() const
{
return !mKeyPath.IsVoid();
}
IDBTransaction* Transaction()
{
return mTransaction;

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

@ -213,6 +213,17 @@ IDBTransaction::OnRequestFinished()
}
}
void
IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName)
{
for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
if (mCreatedObjectStores[i]->Name() == aName) {
mCreatedObjectStores.RemoveElementAt(i);
break;
}
}
}
void
IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
{
@ -406,7 +417,7 @@ IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
);
}
return GetCachedStatement(
"INSERT INTO ai_index_data "
"INSERT OR IGNORE INTO ai_index_data "
"(index_id, ai_object_data_id, value) "
"VALUES (:index_id, :object_data_id, :value)"
);
@ -419,7 +430,7 @@ IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
);
}
return GetCachedStatement(
"INSERT INTO index_data ("
"INSERT OR IGNORE INTO index_data ("
"index_id, object_data_id, object_data_key, value) "
"VALUES (:index_id, :object_data_id, :object_data_key, :value)"
);

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

@ -103,6 +103,8 @@ public:
void OnNewRequest();
void OnRequestFinished();
void ReleaseCachedObjectStore(const nsAString& aName);
void SetTransactionListener(IDBTransactionListener* aListener);
bool StartSavepoint();

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

@ -51,7 +51,7 @@
#include "nsStringGlue.h"
#include "nsTArray.h"
#define DB_SCHEMA_VERSION 6
#define DB_SCHEMA_VERSION 8
#define BEGIN_INDEXEDDB_NAMESPACE \
namespace mozilla { namespace dom { namespace indexedDB {

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

@ -122,9 +122,9 @@ CreateTables(mozIStorageConnection* aDBConn)
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store ("
"id INTEGER PRIMARY KEY, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"auto_increment INTEGER NOT NULL DEFAULT 0, "
"name TEXT NOT NULL, "
"key_path TEXT, "
"UNIQUE (name)"
");"
));
@ -165,6 +165,7 @@ CreateTables(mozIStorageConnection* aDBConn)
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"multientry INTEGER NOT NULL DEFAULT 0, "
"object_store_autoincrement INTERGER NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (object_store_id, name), "
@ -753,6 +754,149 @@ UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
return NS_OK;
}
nsresult
UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
{
mozStorageTransaction transaction(aConnection, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
// Turn off foreign key constraints before we do anything here.
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA foreign_keys = OFF;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TEMPORARY TABLE temp_upgrade ("
"id, "
"name, "
"key_path, "
"auto_increment, "
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO temp_upgrade "
"SELECT id, name, key_path, auto_increment "
"FROM object_store;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE object_store;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store ("
"id INTEGER PRIMARY KEY, "
"auto_increment INTEGER NOT NULL DEFAULT 0, "
"name TEXT NOT NULL, "
"key_path TEXT, "
"UNIQUE (name)"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO object_store "
"SELECT id, auto_increment, name, nullif(key_path, '') "
"FROM temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->SetSchemaVersion(7);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
{
mozStorageTransaction transaction(aConnection, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
// Turn off foreign key constraints before we do anything here.
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA foreign_keys = OFF;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TEMPORARY TABLE temp_upgrade ("
"id, "
"object_store_id, "
"name, "
"key_path, "
"unique_index, "
"object_store_autoincrement, "
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO temp_upgrade "
"SELECT id, object_store_id, name, key_path, "
"unique_index, object_store_autoincrement, "
"FROM object_store_index;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE object_store_index;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store_index ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"multientry INTEGER NOT NULL, "
"object_store_autoincrement INTERGER NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (object_store_id, name), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO object_store_index "
"SELECT id, object_store_id, name, key_path, "
"unique_index, 0, object_store_autoincrement, "
"FROM temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->SetSchemaVersion(8);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
CreateDatabaseConnection(const nsAString& aName,
nsIFile* aDBFile,
@ -804,7 +948,7 @@ CreateDatabaseConnection(const nsAString& aName,
}
else if (schemaVersion != DB_SCHEMA_VERSION) {
// This logic needs to change next time we change the schema!
PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 6);
PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 8);
#define UPGRADE_SCHEMA_CASE(_from, _to) \
if (schemaVersion == _from) { \
@ -819,6 +963,8 @@ CreateDatabaseConnection(const nsAString& aName,
UPGRADE_SCHEMA_CASE(4, 5)
UPGRADE_SCHEMA_CASE(5, 6)
UPGRADE_SCHEMA_CASE(6, 7)
UPGRADE_SCHEMA_CASE(7, 8)
#undef UPGRADE_SCHEMA_CASE

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

@ -60,8 +60,8 @@ public:
bool aForDeletion)
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
mForDeletion(aForDeletion), mCurrentVersion(0),
mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0), mLastObjectStoreId(0),
mForDeletion(aForDeletion), mDatabaseId(nsnull), mCurrentVersion(0),
mDataVersion(DB_SCHEMA_VERSION), mLastObjectStoreId(0),
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK)
{
NS_ASSERTION(!aForDeletion || !aRequestedVersion,

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

@ -47,7 +47,7 @@ interface nsIIDBRequest;
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBIndex for more
* information.
*/
[scriptable, builtinclass, uuid(1da60889-3db4-4f66-9fd7-b78c1e7969b7)]
[scriptable, builtinclass, uuid(fcb9a158-833e-4aa9-ab19-ab90cbb50afc)]
interface nsIIDBIndex : nsISupports
{
readonly attribute DOMString name;
@ -58,6 +58,8 @@ interface nsIIDBIndex : nsISupports
readonly attribute boolean unique;
readonly attribute boolean multiEntry;
readonly attribute nsIIDBObjectStore objectStore;
[implicit_jscontext]

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

@ -84,6 +84,7 @@ TEST_FILES = \
test_indexes_bad_values.html \
test_key_requirements.html \
test_leaving_page.html \
test_multientry.html \
test_objectCursors.html \
test_objectStore_inline_autoincrement_key_added_on_put.html \
test_objectStore_remove_values.html \

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

@ -18,151 +18,195 @@
// Test object stores
const name = window.location.pathname;
const objectStoreInfo = [
{ name: "a", options: { keyPath: "id"} },
{ name: "b", options: { keyPath: "foo.id"} },
{ name: "c", options: { keyPath: ""} },
{ name: "d", options: { keyPath: "foo..id"}, exception: true },
{ name: "e", options: { keyPath: "foo."}, exception: true },
{ name: "f", options: { keyPath: "foo.bar" } },
{ name: "g", options: { keyPath: "fo o" }, exception: true},
{ name: "h", options: { keyPath: "foo " }, exception: true},
{ name: "i", options: { keyPath: "foo[bar]" }, exception: true },
{ name: "j", options: { keyPath: "$('id').stuff" }, exception: true },
{ name: "k", options: { keyPath: "foo.2.bar" }, exception: true }
const keyPaths = [
{ keyPath: "id", value: { id: 5 }, key: 5 },
{ keyPath: "id", value: { id: "14", iid: 12 }, key: "14" },
{ keyPath: "id", value: { iid: "14", id: 12 }, key: 12 },
{ keyPath: "id", value: {} },
{ keyPath: "id", value: { id: {} } },
{ keyPath: "id", value: { id: /x/ } },
{ keyPath: "id", value: 2 },
{ keyPath: "id", value: undefined },
{ keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 },
{ keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" },
{ keyPath: "foo.id", value: { foo: { id: undefined } } },
{ keyPath: "foo.id", value: { foo: 47 } },
{ keyPath: "foo.id", value: {} },
{ keyPath: "", value: "foopy", key: "foopy" },
{ keyPath: "", value: 2, key: 2 },
{ keyPath: "", value: undefined },
{ keyPath: "", value: { id: 12 } },
{ keyPath: "", value: /x/ },
{ keyPath: "foo.bar", value: { baz: 1, foo: { baz2: 2, bar: "xo" } }, key: "xo" },
{ keyPath: "foo.bar.baz", value: { foo: { bar: { bazz: 16, baz: 17 } } }, key: 17 },
{ keyPath: "foo..id", exception: true },
{ keyPath: "foo.", exception: true },
{ keyPath: "fo o", exception: true },
{ keyPath: "foo ", exception: true },
{ keyPath: "foo[bar]",exception: true },
{ keyPath: "$('id').stuff", exception: true },
{ keyPath: "foo.2.bar", exception: true },
{ keyPath: "foo. .bar", exception: true },
{ keyPath: ".bar", exception: true },
];
const indexInfo = [
{ name: "1", keyPath: "id" },
{ name: "2", keyPath: "foo..id", exception: true },
{ name: "3", keyPath: "foo.", exception: true },
{ name: "4", keyPath: "foo.baz" },
{ name: "5", keyPath: "fo o", exception: true },
{ name: "6", keyPath: "foo ", exception: true },
{ name: "7", keyPath: "foo[bar]", exception: true },
{ name: "8", keyPath: "$('id').stuff", exception: true },
{ name: "9", keyPath: "foo.2.bar", exception: true },
{ name: "10", keyPath: "foo.bork" },
];
let request = mozIndexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let openRequest = mozIndexedDB.open(name, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
for (let i = 0; i < objectStoreInfo.length; i++) {
let info = objectStoreInfo[i];
try {
let objectStore = info.hasOwnProperty("options") ?
db.createObjectStore(info.name, info.options) :
db.createObjectStore(info.name);
ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
} catch (e) {
ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
ok(e instanceof DOMException, "Got a DOM Exception");
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
let stores = {};
// Test creating object stores and inserting data
for (let i = 0; i < keyPaths.length; i++) {
let info = keyPaths[i];
let test = " for objectStore test " + JSON.stringify(info);
if (!stores[info.keyPath]) {
try {
let objectStore = db.createObjectStore(info.keyPath, { keyPath: info.keyPath });
ok(!("exception" in info), "shouldn't throw" + test);
is(objectStore.keyPath, info.keyPath, "correct keyPath property" + test);
stores[info.keyPath] = objectStore;
} catch (e) {
ok("exception" in info, "should throw" + test);
ok(e instanceof DOMException, "Got a DOM Exception" + test);
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
continue;
}
}
let store = stores[info.keyPath];
try {
request = store.add(info.value);
ok("key" in info, "successfully created request to insert value" + test);
} catch (e) {
ok(!("key" in info), "threw when attempted to insert" + test);
ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR error" + test);
continue;
}
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let e = yield;
is(e.type, "success", "inserted successfully" + test);
is(e.target, request, "expected target" + test);
is(request.result, info.key, "found correct key" + test);
store.clear().onsuccess = grabEventAndContinueHandler;
yield;
}
request.onsuccess = grabEventAndContinueHandler;
yield;
// Attempt to create indexes and insert data
let store = db.createObjectStore("indexStore");
let indexes = {};
for (let i = 0; i < keyPaths.length; i++) {
let test = " for index test " + JSON.stringify(info);
let info = keyPaths[i];
if (!indexes[info.keyPath]) {
try {
let index = store.createIndex(info.keyPath, info.keyPath);
ok(!("exception" in info), "shouldn't throw" + test);
is(index.keyPath, info.keyPath, "index has correct keyPath property" + test);
indexes[info.keyPath] = index;
} catch (e) {
ok("exception" in info, "should throw" + test);
ok(e instanceof DOMException, "Got a DOM Exception" + test);
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
continue;
}
}
let index = indexes[info.keyPath];
let trans = db.transaction(["f"], IDBTransaction.READ_WRITE);
let objectStore = trans.objectStore("f");
request = store.add(info.value, 1);
if ("key" in info) {
index.getKey(info.key).onsuccess = grabEventAndContinueHandler;
e = yield;
is(e.target.result, 1, "found value when reading" + test);
}
else {
index.count().onsuccess = grabEventAndContinueHandler;
e = yield;
is(e.target.result, 0, "should be empty" + test);
}
objectStore.put({foo: {baz: -1, bar: 72, bork: true}});
objectStore.put({foo: {baz: 2, bar: 1, bork: false}});
store.clear().onsuccess = grabEventAndContinueHandler;
yield;
}
// Autoincrement and complex key paths
let aitests = [{ v: {}, k: 1, res: { foo: { id: 1 }} },
{ v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 }} },
{ v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 }} },
{ v: { v: "x", foo: { x: "y" } }, k: 4, res: { v: "x", foo: { x: "y", id: 4 }} },
{ v: { value: 2, foo: { id: 10 }}, k: 10 },
{ v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 }} },
{ v: true, },
{ v: { value: 2, foo: 12 }, },
{ v: { foo: { id: true }}, },
{ v: { foo: { x: 5, id: {} }}, },
{ v: undefined, },
{ v: { foo: undefined }, },
{ v: { foo: { id: undefined }}, },
{ v: null, },
{ v: { foo: null }, },
{ v: { foo: { id: null }}, },
];
store = db.createObjectStore("gen", { keyPath: "foo.id", autoIncrement: true });
for (let i = 0; i < aitests.length; ++i) {
let info = aitests[i];
let test = " for autoIncrement test " + JSON.stringify(info);
let preValue = JSON.stringify(info.v);
if ("k" in info) {
store.add(info.v).onsuccess = grabEventAndContinueHandler;
is(JSON.stringify(info.v), preValue, "put didn't modify value" + test);
}
else {
try {
store.add(info.v);
ok(false, "should throw" + test);
}
catch(e) {
ok(true, "did throw" + test);
ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR" + test);
is(JSON.stringify(info.v), preValue, "failing put didn't modify value" + test);
continue;
}
}
let e = yield;
is(e.target.result, info.k, "got correct return key" + test);
store.get(info.k).onsuccess = grabEventAndContinueHandler;
e = yield;
is(JSON.stringify(e.target.result), JSON.stringify(info.res || info.v),
"expected value stored" + test);
}
// Can't handle autoincrement and empty keypath
try {
objectStore.put({foo: {}});
ok(false, "Should have thrown!");
} catch (e) {
ok(true, "Putting an object without the key should throw");
store = db.createObjectStore("storefail", { keyPath: "", autoIncrement: true });
ok(false, "Should have thrown when creating empty-keypath autoincrement store");
}
catch(e) {
ok(true, "Did throw when creating empty-keypath autoincrement store");
ok(e instanceof DOMException, "Got a DOMException when creating empty-keypath autoincrement store");
is(e.code, DOMException.INVALID_ACCESS_ERR, "expect a INVALID_ACCESS_ERR when creating empty-keypath autoincrement store");
}
trans.onerror = errorHandler;
trans.oncomplete = grabEventAndContinueHandler;
openRequest.onsuccess = grabEventAndContinueHandler;
yield;
let trans = db.transaction(["f"], IDBTransaction.READ);
let objectStore = trans.objectStore("f");
let request = objectStore.openCursor();
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let cursor = event.target.result;
is(cursor.value.foo.baz, 2, "got things in the right order");
cursor.continue();
let event = yield
let cursor = event.target.result;
is(cursor.value.foo.baz, -1, "got things in the right order");
db.close();
// Test indexes
let request = mozIndexedDB.open(name, 2);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
let trans = event.target.transaction;
let objectStore = trans.objectStore("f");
let indexes = [];
for (let i = 0; i < indexInfo.length; i++) {
let info = indexInfo[i];
try {
indexes[i] = info.hasOwnProperty("options") ?
objectStore.createIndex(info.name, info.keyPath, info.options) :
objectStore.createIndex(info.name, info.keyPath);
ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
} catch (e) {
ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
ok(e instanceof DOMException, "Got a DOM Exception");
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
}
}
request.onsuccess = grabEventAndContinueHandler;
yield;
let trans = db.transaction(["f"], IDBTransaction.READ);
let objectStore = trans.objectStore("f");
let request = objectStore.index("4").openCursor();
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let cursor = event.target.result;
is(cursor.value.foo.bar, 72, "got things in the right order");
cursor.continue();
yield;
is(cursor.value.foo.bar, 1, "got things in the right order");
let request = objectStore.index("10").openCursor();
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
is(event.target.result, null, "should have no results");
finishTest();
yield;
}

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

@ -86,7 +86,7 @@
is(objectStore.name, name, "Bad name");
is(objectStore.keyPath, info.options && info.options.keyPath ?
info.options.keyPath : "",
info.options.keyPath : null,
"Bad keyPath");
if(objectStore.indexNames.length, 0, "Bad indexNames");

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

@ -0,0 +1,230 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
// Test object stores
let openRequest = mozIndexedDB.open(window.location.pathname, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
let tests =
[{ add: { x: 1, id: 1 },
indexes:[{ v: 1, k: 1 }] },
{ add: { x: [2, 3], id: 2 },
indexes:[{ v: 1, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 }] },
{ put: { x: [2, 4], id: 1 },
indexes:[{ v: 2, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 },
{ v: 4, k: 1 }] },
{ add: { x: [5, 6, 5, -2, 3], id: 3 },
indexes:[{ v:-2, k: 3 },
{ v: 2, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 },
{ v: 3, k: 3 },
{ v: 4, k: 1 },
{ v: 5, k: 3 },
{ v: 6, k: 3 }] },
{ delete: IDBKeyRange.bound(1, 3),
indexes:[] },
{ put: { x: ["food", {}, false, undefined, /x/, [73, false]], id: 2 },
indexes:[{ v: "food", k: 2 }] },
{ add: { x: [{}, /x/, -12, "food", null, [false], undefined], id: 3 },
indexes:[{ v: -12, k: 3 },
{ v: "food", k: 2 },
{ v: "food", k: 3 }] },
{ put: { x: [], id: 2 },
indexes:[{ v: -12, k: 3 },
{ v: "food", k: 3 }] },
{ put: { x: { y: 3 }, id: 3 },
indexes:[] },
{ add: { x: false, id: 7 },
indexes:[] },
{ delete: IDBKeyRange.lowerBound(0),
indexes:[] },
];
let store = db.createObjectStore("mystore", { keyPath: "id" });
let index = store.createIndex("myindex", "x", { multiEntry: true });
is(index.multiEntry, true, "index created with multiEntry");
let i;
for (i = 0; i < tests.length; ++i) {
let test = tests[i];
let testName = " for " + JSON.stringify(test);
let req;
if (test.add) {
req = store.add(test.add);
}
else if (test.put) {
req = store.put(test.put);
}
else if (test.delete) {
req = store.delete(test.delete);
}
else {
ok(false, "borked test");
}
req.onsuccess = grabEventAndContinueHandler;
let e = yield;
req = index.openKeyCursor();
req.onsuccess = grabEventAndContinueHandler;
for (let j = 0; j < test.indexes.length; ++j) {
e = yield;
is(req.result.key, test.indexes[j].v, "found expected index key at index " + j + testName);
is(req.result.primaryKey, test.indexes[j].k, "found expected index primary key at index " + j + testName);
req.result.continue();
}
e = yield;
is(req.result, undefined, "exhausted indexes");
let tempIndex = store.createIndex("temp index", "x", { multiEntry: true });
req = tempIndex.openKeyCursor();
req.onsuccess = grabEventAndContinueHandler;
for (let j = 0; j < test.indexes.length; ++j) {
e = yield;
is(req.result.key, test.indexes[j].v, "found expected temp index key at index " + j + testName);
is(req.result.primaryKey, test.indexes[j].k, "found expected temp index primary key at index " + j + testName);
req.result.continue();
}
e = yield;
is(req.result, undefined, "exhausted temp index");
store.deleteIndex("temp index");
}
// Unique indexes
tests =
[{ add: { x: 1, id: 1 },
indexes:[{ v: 1, k: 1 }] },
{ add: { x: [2, 3], id: 2 },
indexes:[{ v: 1, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 }] },
{ put: { x: [2, 4], id: 3 },
fail: true },
{ put: { x: [1, 4], id: 1 },
indexes:[{ v: 1, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 },
{ v: 4, k: 1 }] },
{ add: { x: [5, 0, 5, 5, 5], id: 3 },
indexes:[{ v: 0, k: 3 },
{ v: 1, k: 1 },
{ v: 2, k: 2 },
{ v: 3, k: 2 },
{ v: 4, k: 1 },
{ v: 5, k: 3 }] },
{ delete: IDBKeyRange.bound(1, 2),
indexes:[{ v: 0, k: 3 },
{ v: 5, k: 3 }] },
{ add: { x: [0, 6], id: 8 },
fail: true },
{ add: { x: 5, id: 8 },
fail: true },
{ put: { x: 0, id: 8 },
fail: true },
];
store.deleteIndex("myindex");
index = store.createIndex("myindex", "x", { multiEntry: true, unique: true });
is(index.multiEntry, true, "index created with multiEntry");
let i;
let indexes;
for (i = 0; i < tests.length; ++i) {
let test = tests[i];
let testName = " for " + JSON.stringify(test);
let req;
if (test.add) {
req = store.add(test.add);
}
else if (test.put) {
req = store.put(test.put);
}
else if (test.delete) {
req = store.delete(test.delete);
}
else {
ok(false, "borked test");
}
if (!test.fail) {
req.onsuccess = grabEventAndContinueHandler;
let e = yield;
indexes = test.indexes;
}
else {
req.onsuccess = unexpectedSuccessHandler;
req.onerror = grabEventAndContinueHandler;
ok(true, "waiting for error");
let e = yield;
ok(true, "got error: " + e.type);
e.preventDefault();
e.stopPropagation();
}
let e;
req = index.openKeyCursor();
req.onsuccess = grabEventAndContinueHandler;
for (let j = 0; j < indexes.length; ++j) {
e = yield;
is(req.result.key, indexes[j].v, "found expected index key at index " + j + testName);
is(req.result.primaryKey, indexes[j].k, "found expected index primary key at index " + j + testName);
req.result.continue();
}
e = yield;
is(req.result, undefined, "exhausted indexes");
let tempIndex = store.createIndex("temp index", "x", { multiEntry: true, unique: true });
req = tempIndex.openKeyCursor();
req.onsuccess = grabEventAndContinueHandler;
for (let j = 0; j < indexes.length; ++j) {
e = yield;
is(req.result.key, indexes[j].v, "found expected temp index key at index " + j + testName);
is(req.result.primaryKey, indexes[j].k, "found expected temp index primary key at index " + j + testName);
req.result.continue();
}
e = yield;
is(req.result, undefined, "exhausted temp index");
store.deleteIndex("temp index");
}
openRequest.onsuccess = grabEventAndContinueHandler;
yield;
let trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
store = trans.objectStore("mystore");
index = store.index("myindex");
is(index.multiEntry, true, "index still is multiEntry");
trans.oncomplete = grabEventAndContinueHandler;
yield;
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

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

@ -32,14 +32,30 @@
is(objectStore.indexNames.length, 0, "Correct indexNames list");
objectStore.createIndex(indexName, "foo");
let index = objectStore.createIndex(indexName, "foo");
is(objectStore.indexNames.length, 1, "Correct indexNames list");
is(objectStore.indexNames.item(0), indexName, "Correct name");
is(objectStore.index(indexName), index, "Correct instance");
objectStore.deleteIndex(indexName);
is(objectStore.indexNames.length, 0, "Correct indexNames list");
try {
objectStore.index(indexName);
ok(false, "should have thrown");
}
catch(ex) {
ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException");
is(ex.code, IDBDatabaseException.NOT_FOUND_ERR, "expect a NOT_FOUND_ERR");
}
let index2 = objectStore.createIndex(indexName, "foo");
isnot(index, index2, "New instance should be created");
is(objectStore.indexNames.length, 1, "Correct recreacted indexNames list");
is(objectStore.indexNames.item(0), indexName, "Correct recreacted name");
is(objectStore.index(indexName), index2, "Correct instance");
finishTest();
yield;

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