merge mc into kiwifox

This commit is contained in:
Benoit Girard 2012-01-31 13:55:51 -05:00
commit 7768764c56
243 changed files with 6674 additions and 2306 deletions

View File

@ -593,30 +593,13 @@ nsAccessible::VisibilityState()
{
PRUint64 vstates = states::INVISIBLE | states::OFFSCREEN;
// We need to check the parent chain for visibility.
nsAccessible* accessible = this;
do {
// We don't want background tab page content to be aggressively invisible.
// Otherwise this foils screen reader virtual buffer caches.
roles::Role role = accessible->Role();
if (role == roles::PROPERTYPAGE || role == roles::PANE)
break;
nsIFrame* frame = accessible->GetFrame();
if (!frame)
return vstates;
const nsIView* view = frame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide)
return vstates;
} while (accessible = accessible->Parent());
nsIFrame* frame = GetFrame();
if (!frame)
return vstates;
const nsCOMPtr<nsIPresShell> shell(GetPresShell());
if (!shell)
return vstates;
// We need to know if at least a kMinPixels around the object is visible,
// otherwise it will be marked states::OFFSCREEN.
@ -644,6 +627,10 @@ nsAccessible::VisibilityState()
}
// XXX Do we really need to cross from content to chrome ancestor?
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
return vstates;
// Assume we are visible enough.
return vstates &= ~states::INVISIBLE;
}

View File

@ -47,6 +47,7 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
MOZ_SAFE_BROWSING=
MOZ_SERVICES_SYNC=
MOZ_WEBSMS_BACKEND=1
MOZ_DISABLE_DOMCRYPTO=1
MOZ_APP_STATIC_INI=1

View File

@ -280,7 +280,7 @@ pref("browser.urlbar.doubleClickSelectsAll", true);
#else
pref("browser.urlbar.doubleClickSelectsAll", false);
#endif
pref("browser.urlbar.autoFill", true);
pref("browser.urlbar.autoFill", false);
// 0: Match anywhere (e.g., middle of words)
// 1: Match on word boundaries and then try matching anywhere
// 2: Match only on word boundaries (e.g., after / or .)
@ -293,7 +293,7 @@ pref("browser.urlbar.maxRichResults", 12);
// The amount of time (ms) to wait after the user has stopped typing
// before starting to perform autocomplete. 50 is the default set in
// autocomplete.xml.
pref("browser.urlbar.delay", 0);
pref("browser.urlbar.delay", 50);
// The special characters below can be typed into the urlbar to either restrict
// the search to visited history, bookmarked, tagged pages; or force a match on

View File

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

View File

@ -73,6 +73,14 @@ li.error > .stylesheet-info > .stylesheet-more > .stylesheet-error-message {
-moz-box-pack: center;
}
.stylesheet-name {
white-space: nowrap;
}
li.unsaved > hgroup > h1 > .stylesheet-name:before {
content: "*";
}
.stylesheet-enabled {
display: -moz-box;
}

View File

@ -34,6 +34,17 @@ let gAddedCount = 0; // to add new stylesheet after the 2 initial stylesheets
let gNewEditor; // to make sure only one new stylesheet got created
let gUpdateCount = 0; // to make sure only one Update event is triggered
let gCommitCount = 0; // to make sure only one Commit event is triggered
let gTransitionEndCount = 0;
function finishOnTransitionEndAndCommit() {
if (gCommitCount && gTransitionEndCount) {
is(gUpdateCount, 1, "received one Update event");
is(gCommitCount, 1, "received one Commit event");
is(gTransitionEndCount, 1, "received one transitionend event");
finish();
}
}
function testEditorAdded(aChrome, aEditor)
{
@ -86,6 +97,16 @@ function testEditorAdded(aChrome, aEditor)
is(aEditor.sourceEditor.getText(), TESTCASE_CSS_SOURCE + "}",
"rule bracket has been auto-closed");
// we know that the testcase above will start a CSS transition
content.addEventListener("transitionend", function () {
gTransitionEndCount++;
let computedStyle = content.getComputedStyle(content.document.body, null);
is(computedStyle.backgroundColor, "rgb(255, 0, 0)",
"content's background color has been updated to red");
executeSoon(finishOnTransitionEndAndCommit);
}, false);
}, gChromeWindow) ;
},
@ -109,22 +130,13 @@ function testEditorAdded(aChrome, aEditor)
is(parseInt(ruleCount), 1,
"new editor shows 1 rule after modification");
let computedStyle = content.getComputedStyle(content.document.body, null);
is(computedStyle.backgroundColor, "rgb(255, 0, 0)",
"content's background color has been updated to red");
ok(!content.document.documentElement.classList.contains(TRANSITION_CLASS),
"StyleEditor's transition class has been removed from content");
executeSoon(function () {
is(gUpdateCount, 1, "received only one Update event (throttle)");
is(gCommitCount, 1, "received only one Commit event (throttle)");
aEditor.removeActionListener(listener);
gNewEditor = null;
aEditor.removeActionListener(listener);
gNewEditor = null;
finish();
});
executeSoon(finishOnTransitionEndAndCommit);
}
};

View File

@ -230,7 +230,7 @@ Tilt.prototype = {
*/
_onTabSelect: function T__onTabSelect()
{
if (this.visualizers[this.currentWindowId]) {
if (this.currentInstance) {
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.SHOWN, null);
} else {
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.HIDDEN, null);
@ -245,10 +245,8 @@ Tilt.prototype = {
* the newly selected node
*/
update: function T_update(aNode) {
let id = this.currentWindowId;
if (this.visualizers[id]) {
this.visualizers[id].presenter.highlightNode(aNode);
if (this.currentInstance) {
this.currentInstance.presenter.highlightNode(aNode);
}
},
@ -277,6 +275,7 @@ Tilt.prototype = {
this._whenShown.bind(this), TILT_NOTIFICATIONS.SHOWN, false);
Services.obs.addObserver(
this._whenHidden.bind(this), TILT_NOTIFICATIONS.HIDDEN, false);
Services.obs.addObserver(function(aSubject, aTopic, aWinId) {
this.destroy(aWinId); }.bind(this),
this.chromeWindow.InspectorUI.INSPECTOR_NOTIFICATIONS.DESTROYED, false);
@ -287,7 +286,7 @@ Tilt.prototype = {
// FIXME: this shouldn't be done here, see bug #705131
let onOpened = function() {
if (this.visualizers[this.currentWindowId]) {
if (this.currentInstance) {
this.chromeWindow.InspectorUI.stopInspecting();
this.inspectButton.disabled = true;
this.highlighterContainer.style.display = "none";
@ -326,8 +325,16 @@ Tilt.prototype = {
*/
get currentWindowId()
{
let gBrowser = this.chromeWindow.gBrowser;
return TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
return TiltUtils.getWindowId(
this.chromeWindow.gBrowser.selectedBrowser.contentWindow);
},
/**
* Gets the visualizer instance for the current tab.
*/
get currentInstance()
{
return this.visualizers[this.currentWindowId];
},
/**

View File

@ -1052,6 +1052,7 @@ TiltVisualizer.Controller.prototype = {
canvas.addEventListener("MozMousePixelScroll", this.onMozScroll, false);
canvas.addEventListener("keydown", this.onKeyDown, false);
canvas.addEventListener("keyup", this.onKeyUp, false);
canvas.addEventListener("keypress", this.onKeyPress, true);
canvas.addEventListener("blur", this.onBlur, false);
// handle resize events to change the arcball dimensions
@ -1074,6 +1075,7 @@ TiltVisualizer.Controller.prototype = {
canvas.removeEventListener("MozMousePixelScroll", this.onMozScroll, false);
canvas.removeEventListener("keydown", this.onKeyDown, false);
canvas.removeEventListener("keyup", this.onKeyUp, false);
canvas.removeEventListener("keypress", this.onKeyPress, true);
canvas.removeEventListener("blur", this.onBlur, false);
presenter.contentWindow.removeEventListener("resize", this.onResize,false);
@ -1217,16 +1219,10 @@ TiltVisualizer.Controller.prototype = {
onKeyUp: function TVC_onKeyUp(e)
{
let code = e.keyCode || e.which;
let tilt = this.presenter.chromeWindow.Tilt;
if (code === e.DOM_VK_ESCAPE) {
tilt.destroy(tilt.currentWindowId, true);
return;
}
if (code === e.DOM_VK_X) {
this.presenter.deleteNode();
}
if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
e.preventDefault();
e.stopPropagation();
@ -1234,6 +1230,20 @@ TiltVisualizer.Controller.prototype = {
}
},
/**
* Called when a key is pressed.
*/
onKeyPress: function TVC_onKeyPress(e)
{
let tilt = this.presenter.chromeWindow.Tilt;
if (e.keyCode === e.DOM_VK_ESCAPE) {
e.preventDefault();
e.stopPropagation();
tilt.destroy(tilt.currentWindowId, true);
}
},
/**
* Called when the canvas looses focus.
*/

View File

@ -31,6 +31,9 @@ function cleanup() {
is(Tilt.visualizers[id], null,
"The current instance of the visualizer wasn't destroyed properly.");
ok(InspectorUI.highlighter && InspectorUI.breadcrumbs,
"The Inspector should not close while Tilt is opened.");
Services.obs.removeObserver(cleanup, DESTROYED);
gBrowser.removeCurrentTab();
finish();

View File

@ -2106,6 +2106,11 @@ panel[dimmed="true"] {
margin-bottom: -1px;
}
#inspector-breadcrumbs > .scrollbutton-up,
#inspector-breadcrumbs > .scrollbutton-down {
-moz-appearance: none;
}
.inspector-breadcrumbs-button {
-moz-appearance: none;
background-color: transparent;

View File

@ -78,6 +78,12 @@
margin: 0 auto;
}
/* CELLS */
.cell {
outline: 1px dashed #ccc;
outline-offset: -1px;
}
/* SITES */
.site {
background-color: #ececec;

View File

@ -78,6 +78,12 @@
margin: 0 auto;
}
/* CELLS */
.cell {
outline: 1px dashed #ccc;
outline-offset: -1px;
}
/* SITES */
.site {
background-color: #ececec;

View File

@ -2786,6 +2786,11 @@ panel[dimmed="true"] {
margin: -1px 0;
}
#inspector-breadcrumbs > .scrollbutton-up,
#inspector-breadcrumbs > .scrollbutton-down {
-moz-appearance: none;
}
.inspector-breadcrumbs-button {
-moz-appearance: none;
background-color: transparent;

View File

@ -78,6 +78,12 @@
margin: 0 auto;
}
/* CELLS */
.cell {
outline: 1px dashed #ccc;
outline-offset: -1px;
}
/* SITES */
.site {
background-color: #ececec;

View File

@ -60,6 +60,12 @@ public interface Actions {
* @param geckoEvent The geckoEvent JSONObject's type
*/
EventExpecter expectGeckoEvent(String geckoEvent);
/**
* Listens for a paint event.
*/
EventExpecter expectPaint();
// Send the string kewsToSend to the application
void sendKeys(String keysToSend);
//Send any of the above keys to the element

View File

@ -52,4 +52,7 @@ public interface Assert {
void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name);
void info(String name, String message);
// robocop-specific asserts
void ispixel(int actual, int r, int g, int b, String name);
}

View File

@ -68,4 +68,11 @@ public interface Driver {
void startFrameRecording();
int stopFrameRecording();
/**
* Get a copy of the painted content region.
* @return A 2-D array of pixels (indexed by y, then x). The pixels
* are in ARGB-8888 format.
*/
int[][] getPaintedSurface();
}

View File

@ -73,20 +73,24 @@ public class FennecNativeActions implements Actions {
// Map of IDs to element names.
private Solo solo;
private Instrumentation instr;
private Activity geckoApp;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Class drawListener;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
private Method getLayerClient;
private Method setDrawListener;
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
this.solo = robocop;
this.instr = instrumentation;
this.geckoApp = activity;
// Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
@ -101,6 +105,11 @@ public class FennecNativeActions implements Actions {
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
getLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
Class gslc = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
drawListener = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
setDrawListener = gslc.getDeclaredMethod("setDrawListener", drawListener);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
@ -205,6 +214,75 @@ public class FennecNativeActions implements Actions {
return null;
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;
DrawListenerProxy(PaintExpecter paintExpecter) {
mPaintExpecter = paintExpecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
Log.i("Robocop", "Received drawFinished notification");
mPaintExpecter.notifyOfEvent();
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
}
class PaintExpecter implements EventExpecter {
private Object mLayerClient;
private boolean mPaintDone;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
mLayerClient = getLayerClient.invoke(geckoApp);
setDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(classLoader, new Class[] { drawListener }, new DrawListenerProxy(this)));
}
void notifyOfEvent() {
try {
setDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
}
public synchronized void blockForEvent() {
while (! mPaintDone) {
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
}
public synchronized boolean eventReceived() {
return mPaintDone;
}
}
public EventExpecter expectPaint() {
try {
return new PaintExpecter();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void sendSpecialKey(SpecialKey button) {
switch( button) {
case DOWN:

View File

@ -243,6 +243,23 @@ public class FennecNativeAssert implements Assert {
ok(pass, name, diag);
}
public void ispixel(int actual, int r, int g, int b, String name) {
// When we read GL pixels the GPU has already processed them and they
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
// against the expected value, we use a little fuzz factor. For the alpha we just
// make sure it is always 0xFF.
int aAlpha = ((actual >> 24) & 0xFF);
int aR = ((actual >> 16) & 0xFF);
int aG = ((actual >> 8) & 0xFF);
int aB = (actual & 0xFF);
boolean pass = (aAlpha == 0xFF) /* alpha */
&& (Math.abs(aR - r) < 8) /* red */
&& (Math.abs(aG - g) < 8) /* green */
&& (Math.abs(aB - b) < 8); /* blue */
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
}
public void todo(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, true);
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");

View File

@ -45,6 +45,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
@ -58,6 +59,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.Long;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.View;
@ -81,6 +83,7 @@ public class FennecNativeDriver implements Driver {
private Method sendGE;
private Method _startFrameRecording;
private Method _stopFrameRecording;
private Method _getPixels;
public FennecNativeDriver(Activity activity, Solo robocop){
this.activity = activity;
@ -107,6 +110,9 @@ public class FennecNativeDriver implements Driver {
Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
Class layerView = classLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
_getPixels = layerView.getDeclaredMethod("getPixels");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
@ -212,6 +218,43 @@ public class FennecNativeDriver implements Driver {
return 0;
}
private GLSurfaceView getSurfaceView() {
for (View v : solo.getCurrentViews()) {
if (v instanceof GLSurfaceView) {
return (GLSurfaceView)v;
}
}
return null;
}
public int[][] getPaintedSurface() {
GLSurfaceView view = getSurfaceView();
if (view == null) {
return null;
}
IntBuffer pixelBuffer;
try {
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
} catch (Exception e) {
e.printStackTrace();
return null;
}
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
int w = view.getWidth();
int h = view.getHeight();
pixelBuffer.position(0);
int[][] pixels = new int[h][w];
for (int y = h - 1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
int agbr = pixelBuffer.get();
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
}
}
return pixels;
}
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {

View File

@ -68,6 +68,7 @@ _TEST_FILES = \
$(TESTPATH)/robocop_blank_01.html \
$(TESTPATH)/robocop_blank_02.html \
$(TESTPATH)/robocop_blank_03.html \
$(TESTPATH)/robocop_boxes.html \
$(NULL)
_ROBOCOP_TOOLS = \

View File

@ -70,5 +70,5 @@ JAVAC_FLAGS = \
-classpath $(JAVA_CLASSPATH) \
-bootclasspath $(JAVA_BOOTCLASSPATH) \
-encoding UTF8 \
-g \
-g:source,lines \
$(NULL)

View File

@ -4906,12 +4906,14 @@ cairo-android)
cairo-gonk)
AC_DEFINE(MOZ_WIDGET_GONK)
AC_DEFINE(MOZ_TOUCH)
MOZ_WIDGET_TOOLKIT=gonk
TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
TK_LIBS='$(MOZ_CAIRO_LIBS)'
MOZ_WEBGL=1
MOZ_PDF_PRINTING=1
MOZ_B2G_RIL=1
MOZ_TOUCH=1
;;
esac
@ -5669,20 +5671,20 @@ if test -n "$MOZ_WEBM"; then
[MOZ_NATIVE_LIBVPX_DEC_TEST=1],
([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found]))
if test -n "$MOZ_NATIVE_LIBVPX_DEC_TEST" ; then
AC_MSG_CHECKING([for libvpx version >= v0.9.7])
dnl We need at least v0.9.7 to fix several crash bugs (for which we
dnl had local patches prior to v0.9.7).
AC_MSG_CHECKING([for libvpx version >= v1.0.0])
dnl We need at least v1.0.0 to fix several crash bugs (for which we
dnl had local patches prior to v1.0.0).
dnl
dnl This is a terrible test for the library version, but we don't
dnl have a good one. There is no version number in a public header,
dnl and testing the headers still doesn't guarantee we link against
dnl the right version. While we could call vpx_codec_version() at
dnl run-time, that would break cross-compiling. There are no
dnl additional exported symbols between the v0.9.7 release and the
dnl v0.9.6 one to check for.
dnl additional exported decoder symbols between the v1.0.0 release
dnl and the v0.9.7 one to check for.
AC_TRY_COMPILE([
#include <vpx/vpx_decoder.h>
#if !defined(VPX_CODEC_USE_INPUT_PARTITION)
#if !defined(VPX_CODEC_USE_INPUT_FRAGMENTS)
#error "test failed."
#endif
],
@ -5693,7 +5695,7 @@ if test -n "$MOZ_WEBM"; then
MOZ_LIBVPX_INCLUDES="-I${LIBVPX_DIR}/include"
MOZ_LIBVPX_LIBS="-L${LIBVPX_DIR}/lib -lvpx"],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([--with-system-libvpx requested but it is not v0.9.7 or later])])
AC_MSG_ERROR([--with-system-libvpx requested but it is not v1.0.0 or later])])
fi
CFLAGS=$_SAVE_CFLAGS
LDFLAGS=$_SAVE_LDFLAGS

View File

@ -178,6 +178,48 @@ enum EventNameType {
EventNameType_All = 0xFFFF
};
/**
* Information retrieved from the <meta name="viewport"> tag. See
* GetViewportInfo for more information on this functionality.
*/
struct ViewportInfo
{
// Default zoom indicates the level at which the display is 'zoomed in'
// initially for the user, upon loading of the page.
double defaultZoom;
// The minimum zoom level permitted by the page.
double minZoom;
// The maximum zoom level permitted by the page.
double maxZoom;
// The width of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 width;
// The height of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 height;
// Whether or not we should automatically size the viewport to the device's
// width. This is true if the document has been optimized for mobile, and
// the width property of a specified <meta name="viewport"> tag is either
// not specified, or is set to the special value 'device-width'.
bool autoSize;
// Whether or not the user can zoom in and out on the page. Default is true.
bool allowZoom;
// This is a holdover from e10s fennec, and might be removed in the future.
// It's a hack to work around bugs that didn't allow zooming of documents
// from within the parent process. It is still used in native Fennec for XUL
// documents, but it should probably be removed.
// Currently, from, within GetViewportInfo(), This is only set to false
// if the document is a XUL document.
bool autoScale;
};
struct EventNameMapping
{
nsIAtom* mAtom;
@ -1489,6 +1531,18 @@ public:
return sScriptBlockerCount == 0;
}
/**
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
* of the document. This can be used in lieu of ProcessViewportInfo(),
* which places the viewport information in the document header instead
* of returning it directly.
*
* NOTE: If the site is optimized for mobile (via the doctype), this
* will return viewport information that specifies default information.
*/
static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
/* Process viewport META data. This gives us information for the scale
* and zoom of a page on mobile devices. We stick the information in
* the document header and use it later on after rendering.

View File

@ -78,8 +78,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0xdc68f070, 0x226d, 0x11e1, \
{ 0xbf, 0xc2, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
{ 0x94671671, 0x9e1b, 0x447a, \
{ 0xad, 0xb7, 0xc3, 0x2e, 0x05, 0x6a, 0x96, 0xc9 } }
/**
* A node of content in a document's content model. This interface
@ -948,6 +948,9 @@ public:
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
virtual bool IsPurple() = 0;
virtual void RemovePurple() = 0;
protected:
/**
* Hook for implementing GetID. This is guaranteed to only be

View File

@ -288,8 +288,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0xd026d280, 0x5b25, 0x41c0, \
{ 0x92, 0xcf, 0x6, 0xf6, 0xf, 0xb, 0x9a, 0xfe } }
{ 0xfcd3b0d1, 0x75db, 0x46c4, \
{ 0xa1, 0xf5, 0x07, 0xc2, 0x09, 0xf8, 0x1f, 0x44 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -1223,6 +1223,13 @@ private:
NodeIsCommonAncestorForRangeInSelection,
// Set if the node is a descendant of a node with the above bit set.
NodeIsDescendantOfCommonAncestorForRangeInSelection,
// Set if CanSkipInCC check has been done for this subtree root.
NodeIsCCMarkedRoot,
// Maybe set if this node is in black subtree.
NodeIsCCBlackTree,
// Maybe set if the node is a root of a subtree
// which needs to be kept in the purple buffer.
NodeIsPurpleRoot,
// Guard value
BooleanFlagCount
};
@ -1270,6 +1277,16 @@ public:
void ClearDescendantOfCommonAncestorForRangeInSelection()
{ ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
void SetCCMarkedRoot(bool aValue)
{ SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); }
void SetInCCBlackTree(bool aValue)
{ SetBoolFlag(NodeIsCCBlackTree, aValue); }
bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); }
void SetIsPurpleRoot(bool aValue)
{ SetBoolFlag(NodeIsPurpleRoot, aValue); }
bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
void SetInDocument() { SetBoolFlag(IsInDocument); }

View File

@ -54,6 +54,13 @@
#include "nsIXULWindow.h"
#include "nsIAppShellService.h"
#include "nsAppShellCID.h"
#include "nsEventListenerManager.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsJSEnvironment.h"
#include "nsInProcessTabChildGlobal.h"
#include "nsFrameLoader.h"
#include "nsGenericElement.h"
static bool sInited = 0;
PRUint32 nsCCUncollectableMarker::sGeneration = 0;
@ -87,29 +94,122 @@ nsCCUncollectableMarker::Init()
rv = obs->AddObserver(marker, "cycle-collector-begin", false);
NS_ENSURE_SUCCESS(rv, rv);
rv = obs->AddObserver(marker, "cycle-collector-forget-skippable", false);
NS_ENSURE_SUCCESS(rv, rv);
sInited = true;
return NS_OK;
}
static void
MarkUserData(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
{
nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
nsGenericElement::MarkUserData(aNode, aKey, aValue, aData);
}
}
static void
MarkUserDataHandler(void* aNode, nsIAtom* aKey, void* aValue, void* aData)
{
nsIDocument* d = static_cast<nsINode*>(aNode)->GetCurrentDoc();
if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
nsGenericElement::MarkUserDataHandler(aNode, aKey, aValue, aData);
}
}
static void
MarkMessageManagers()
{
nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
do_GetService("@mozilla.org/globalmessagemanager;1");
if (!globalMM) {
return;
}
globalMM->MarkForCC();
PRUint32 childCount = 0;
globalMM->GetChildCount(&childCount);
for (PRUint32 i = 0; i < childCount; ++i) {
nsCOMPtr<nsITreeItemFrameMessageManager> windowMM;
globalMM->GetChildAt(i, getter_AddRefs(windowMM));
if (!windowMM) {
continue;
}
windowMM->MarkForCC();
PRUint32 tabChildCount = 0;
windowMM->GetChildCount(&tabChildCount);
for (PRUint32 j = 0; j < tabChildCount; ++j) {
nsCOMPtr<nsITreeItemFrameMessageManager> tabMM;
windowMM->GetChildAt(j, getter_AddRefs(tabMM));
if (!tabMM) {
continue;
}
tabMM->MarkForCC();
//XXX hack warning, but works, since we know that
// callback data is frameloader.
void* cb = static_cast<nsFrameMessageManager*>(tabMM.get())->
GetCallbackData();
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
if (fl) {
nsIDOMEventTarget* et = fl->GetTabChildGlobalAsEventTarget();
if (!et) {
continue;
}
static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
nsEventListenerManager* elm = et->GetListenerManager(false);
if (elm) {
elm->UnmarkGrayJSListeners();
}
}
}
}
}
void
MarkContentViewer(nsIContentViewer* aViewer)
MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
bool aPrepareForCC)
{
if (!aViewer) {
return;
}
nsIDocument *doc = aViewer->GetDocument();
if (doc) {
if (doc &&
doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
if (aCleanupJS) {
nsEventListenerManager* elm = doc->GetListenerManager(false);
if (elm) {
elm->UnmarkGrayJSListeners();
}
nsCOMPtr<nsIDOMEventTarget> win = do_QueryInterface(doc->GetInnerWindow());
if (win) {
elm = win->GetListenerManager(false);
if (elm) {
elm->UnmarkGrayJSListeners();
}
static_cast<nsGlobalWindow*>(win.get())->UnmarkGrayTimers();
}
doc->PropertyTable(DOM_USER_DATA_HANDLER)->
EnumerateAll(MarkUserDataHandler, &nsCCUncollectableMarker::sGeneration);
} else if (aPrepareForCC) {
// Unfortunately we need to still mark user data just before running CC so
// that it has the right generation.
doc->PropertyTable(DOM_USER_DATA)->
EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
}
}
}
void MarkDocShell(nsIDocShellTreeNode* aNode);
void MarkDocShell(nsIDocShellTreeNode* aNode, bool aCleanupJS,
bool aPrepareForCC);
void
MarkSHEntry(nsISHEntry* aSHEntry)
MarkSHEntry(nsISHEntry* aSHEntry, bool aCleanupJS, bool aPrepareForCC)
{
if (!aSHEntry) {
return;
@ -117,13 +217,13 @@ MarkSHEntry(nsISHEntry* aSHEntry)
nsCOMPtr<nsIContentViewer> cview;
aSHEntry->GetContentViewer(getter_AddRefs(cview));
MarkContentViewer(cview);
MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
nsCOMPtr<nsIDocShellTreeItem> child;
PRInt32 i = 0;
while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, getter_AddRefs(child))) &&
child) {
MarkDocShell(child);
MarkDocShell(child, aCleanupJS, aPrepareForCC);
}
nsCOMPtr<nsISHContainer> shCont = do_QueryInterface(aSHEntry);
@ -132,13 +232,13 @@ MarkSHEntry(nsISHEntry* aSHEntry)
for (i = 0; i < count; ++i) {
nsCOMPtr<nsISHEntry> childEntry;
shCont->GetChildAt(i, getter_AddRefs(childEntry));
MarkSHEntry(childEntry);
MarkSHEntry(childEntry, aCleanupJS, aPrepareForCC);
}
}
void
MarkDocShell(nsIDocShellTreeNode* aNode)
MarkDocShell(nsIDocShellTreeNode* aNode, bool aCleanupJS, bool aPrepareForCC)
{
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(aNode);
if (!shell) {
@ -147,7 +247,7 @@ MarkDocShell(nsIDocShellTreeNode* aNode)
nsCOMPtr<nsIContentViewer> cview;
shell->GetContentViewer(getter_AddRefs(cview));
MarkContentViewer(cview);
MarkContentViewer(cview, aCleanupJS, aPrepareForCC);
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(shell);
nsCOMPtr<nsISHistory> history;
@ -160,7 +260,7 @@ MarkDocShell(nsIDocShellTreeNode* aNode)
history->GetEntryAtIndex(i, false, getter_AddRefs(historyEntry));
nsCOMPtr<nsISHEntry> shEntry = do_QueryInterface(historyEntry);
MarkSHEntry(shEntry);
MarkSHEntry(shEntry, aCleanupJS, aPrepareForCC);
}
}
@ -169,12 +269,13 @@ MarkDocShell(nsIDocShellTreeNode* aNode)
for (i = 0; i < childCount; ++i) {
nsCOMPtr<nsIDocShellTreeItem> child;
aNode->GetChildAt(i, getter_AddRefs(child));
MarkDocShell(child);
MarkDocShell(child, aCleanupJS, aPrepareForCC);
}
}
void
MarkWindowList(nsISimpleEnumerator* aWindowList)
MarkWindowList(nsISimpleEnumerator* aWindowList, bool aCleanupJS,
bool aPrepareForCC)
{
nsCOMPtr<nsISupports> iter;
while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
@ -184,7 +285,7 @@ MarkWindowList(nsISimpleEnumerator* aWindowList)
nsCOMPtr<nsIDocShellTreeNode> rootDocShell =
do_QueryInterface(window->GetDocShell());
MarkDocShell(rootDocShell);
MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
}
}
}
@ -202,13 +303,23 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
// No need for kungFuDeathGrip here, yay observerservice!
obs->RemoveObserver(this, "xpcom-shutdown");
obs->RemoveObserver(this, "cycle-collector-begin");
obs->RemoveObserver(this, "cycle-collector-forget-skippable");
sGeneration = 0;
return NS_OK;
}
NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin"), "wrong topic");
NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
!strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
// JS cleanup can be slow. Do it only if there has been a GC.
bool cleanupJS =
!nsJSContext::CleanupSinceLastGC() &&
!strcmp(aTopic, "cycle-collector-forget-skippable");
bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
// Increase generation to effectivly unmark all current objects
if (!++sGeneration) {
@ -225,7 +336,7 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
rv = med->GetEnumerator(nsnull, getter_AddRefs(windowList));
NS_ENSURE_SUCCESS(rv, rv);
MarkWindowList(windowList);
MarkWindowList(windowList, cleanupJS, prepareForCC);
}
nsCOMPtr<nsIWindowWatcher> ww =
@ -234,7 +345,7 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
rv = ww->GetWindowEnumerator(getter_AddRefs(windowList));
NS_ENSURE_SUCCESS(rv, rv);
MarkWindowList(windowList);
MarkWindowList(windowList, cleanupJS, prepareForCC);
}
nsCOMPtr<nsIAppShellService> appShell =
@ -246,10 +357,15 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
nsCOMPtr<nsIDocShell> shell;
hw->GetDocShell(getter_AddRefs(shell));
nsCOMPtr<nsIDocShellTreeNode> shellTreeNode = do_QueryInterface(shell);
MarkDocShell(shellTreeNode);
MarkDocShell(shellTreeNode, cleanupJS, prepareForCC);
}
}
if (cleanupJS) {
nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration);
MarkMessageManagers();
}
#ifdef MOZ_XUL
nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
if (xulCache) {

View File

@ -211,6 +211,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "mozilla/Preferences.h"
#include "nsWrapperCacheInlines.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMWindowUtils.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsUnicharUtils.h"
@ -221,6 +223,17 @@ using namespace mozilla;
const char kLoadAsData[] = "loadAsData";
/**
* Default values for the ViewportInfo structure.
*/
static const float kViewportMinScale = 0.0;
static const float kViewportMaxScale = 10.0;
static const PRUint32 kViewportMinWidth = 200;
static const PRUint32 kViewportMaxWidth = 10000;
static const PRUint32 kViewportMinHeight = 223;
static const PRUint32 kViewportMaxHeight = 10000;
static const PRInt32 kViewportDefaultScreenWidth = 980;
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -421,6 +434,8 @@ nsContentUtils::Init()
"dom.event.handling-user-input-time-limit",
1000);
nsGenericElement::InitCCCallbacks();
sInitialized = true;
return NS_OK;
@ -4554,6 +4569,198 @@ static void ProcessViewportToken(nsIDocument *aDocument,
#define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
(c == '\t') || (c == '\n') || (c == '\r'))
/* static */
ViewportInfo
nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
{
ViewportInfo ret;
ret.defaultZoom = 1.0;
ret.autoSize = true;
ret.allowZoom = true;
ret.autoScale = true;
// If the docType specifies that we are on a site optimized for mobile,
// then we want to return specially crafted defaults for the viewport info.
nsCOMPtr<nsIDOMDocument>
domDoc(do_QueryInterface(aDocument));
nsCOMPtr<nsIDOMDocumentType> docType;
nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
if (NS_SUCCEEDED(rv) && docType) {
nsAutoString docId;
rv = docType->GetPublicId(docId);
if (NS_SUCCEEDED(rv)) {
if ((docId.Find("WAP") != -1) ||
(docId.Find("Mobile") != -1) ||
(docId.Find("WML") != -1))
{
return ret;
}
}
}
if (aDocument->IsXUL()) {
ret.autoScale = false;
return ret;
}
nsIDOMWindow* window = aDocument->GetWindow();
nsCOMPtr<nsIDOMWindowUtils> windowUtils(do_GetInterface(window));
if (!windowUtils) {
return ret;
}
nsAutoString handheldFriendly;
aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
if (handheldFriendly.EqualsLiteral("true")) {
return ret;
}
PRInt32 errorCode;
nsAutoString minScaleStr;
aDocument->GetHeaderData(nsGkAtoms::minimum_scale, minScaleStr);
float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
if (errorCode) {
scaleMinFloat = kViewportMinScale;
}
scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
nsAutoString maxScaleStr;
aDocument->GetHeaderData(nsGkAtoms::maximum_scale, maxScaleStr);
// We define a special error code variable for the scale and max scale,
// because they are used later (see the width calculations).
PRInt32 scaleMaxErrorCode;
float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
if (scaleMaxErrorCode) {
scaleMaxFloat = kViewportMaxScale;
}
scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
nsAutoString scaleStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
PRInt32 scaleErrorCode;
float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
nsAutoString widthStr, heightStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
bool autoSize = false;
if (widthStr.EqualsLiteral("device-width")) {
autoSize = true;
}
if (widthStr.IsEmpty() &&
(heightStr.EqualsLiteral("device-height") ||
scaleFloat == 1.0))
{
autoSize = true;
}
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
// purposes (bug 706198), but it will need to be changed in the future to be
// more correct when we bring the rest of the viewport code into platform.
// We actually want the size of the content area, in the event that we don't
// have any metadata about the width and/or height. On mobile, the screen size
// and the size of the content area are very close, or the same value.
// In XUL fennec, the content area is the size of the <browser> widget, but
// in native fennec, the content area is the size of the Gecko LayerView
// object.
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult result;
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
PRUint32 width = widthStr.ToInteger(&errorCode);
if (errorCode) {
if (autoSize) {
width = screenWidth;
} else {
width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
}
}
width = NS_MIN(width, kViewportMaxWidth);
width = NS_MAX(width, kViewportMinWidth);
// Also recalculate the default zoom, if it wasn't specified in the metadata,
// and the width is specified.
if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
}
PRUint32 height = heightStr.ToInteger(&errorCode);
if (errorCode) {
height = width * ((float)screenHeight / screenWidth);
}
// If height was provided by the user, but width wasn't, then we should
// calculate the width.
if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
width = (PRUint32) ((height * screenWidth) / screenHeight);
}
height = NS_MIN(height, kViewportMaxHeight);
height = NS_MAX(height, kViewportMinHeight);
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (!scaleStr.IsEmpty() && !scaleErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleFloat));
} else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleMaxFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleMaxFloat));
}
bool allowZoom = true;
nsAutoString userScalable;
aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
if ((userScalable.EqualsLiteral("0")) ||
(userScalable.EqualsLiteral("no")) ||
(userScalable.EqualsLiteral("false"))) {
allowZoom = false;
}
ret.allowZoom = allowZoom;
ret.width = width;
ret.height = height;
ret.defaultZoom = scaleFloat;
ret.minZoom = scaleMinFloat;
ret.maxZoom = scaleMaxFloat;
ret.autoSize = autoSize;
return ret;
}
/* static */
nsresult
nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,

View File

@ -35,51 +35,18 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMBlobBuilder.h"
#include "jstypedarray.h"
#include "nsAutoPtr.h"
#include "nsDOMClassInfoID.h"
#include "nsDOMFile.h"
#include "nsIMultiplexInputStream.h"
#include "nsStringStream.h"
#include "nsTArray.h"
#include "nsJSUtils.h"
#include "nsContentUtils.h"
#include "CheckedInt.h"
#include "mozilla/StdInt.h"
using namespace mozilla;
class nsDOMMultipartFile : public nsDOMFileBase
{
public:
// Create as a file
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aName,
const nsAString& aContentType)
: nsDOMFileBase(aName, aContentType, UINT64_MAX),
mBlobs(aBlobs)
{
}
// Create as a blob
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aContentType)
: nsDOMFileBase(aContentType, UINT64_MAX),
mBlobs(aBlobs)
{
}
already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType);
NS_IMETHOD GetSize(PRUint64*);
NS_IMETHOD GetInternalStream(nsIInputStream**);
protected:
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
};
NS_IMETHODIMP
nsDOMMultipartFile::GetSize(PRUint64* aLength)
{
@ -199,67 +166,6 @@ nsDOMMultipartFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
return blob.forget();
}
class nsDOMBlobBuilder : public nsIDOMMozBlobBuilder
{
public:
nsDOMBlobBuilder()
: mData(nsnull), mDataLen(0), mDataBufferLen(0)
{}
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZBLOBBUILDER
protected:
nsresult AppendVoidPtr(void* aData, PRUint32 aLength);
nsresult AppendString(JSString* aString, JSContext* aCx);
nsresult AppendBlob(nsIDOMBlob* aBlob);
nsresult AppendArrayBuffer(JSObject* aBuffer);
bool ExpandBufferSize(PRUint64 aSize)
{
if (mDataBufferLen >= mDataLen + aSize) {
mDataLen += aSize;
return true;
}
// Start at 1 or we'll loop forever.
CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1);
while (bufferLen.valid() && bufferLen.value() < mDataLen + aSize)
bufferLen *= 2;
if (!bufferLen.valid())
return false;
// PR_ memory functions are still fallible
void* data = PR_Realloc(mData, bufferLen.value());
if (!data)
return false;
mData = data;
mDataBufferLen = bufferLen.value();
mDataLen += aSize;
return true;
}
void Flush() {
if (mData) {
// If we have some data, create a blob for it
// and put it on the stack
nsCOMPtr<nsIDOMBlob> blob =
new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
mBlobs.AppendElement(blob);
mData = nsnull; // The nsDOMMemoryFile takes ownership of the buffer
mDataLen = 0;
mDataBufferLen = 0;
}
}
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
void* mData;
PRUint64 mDataLen;
PRUint64 mDataBufferLen;
};
DOMCI_DATA(MozBlobBuilder, nsDOMBlobBuilder)
NS_IMPL_ADDREF(nsDOMBlobBuilder)
@ -271,7 +177,7 @@ NS_INTERFACE_MAP_BEGIN(nsDOMBlobBuilder)
NS_INTERFACE_MAP_END
nsresult
nsDOMBlobBuilder::AppendVoidPtr(void* aData, PRUint32 aLength)
nsDOMBlobBuilder::AppendVoidPtr(const void* aData, PRUint32 aLength)
{
NS_ENSURE_ARG_POINTER(aData);
@ -319,6 +225,14 @@ nsDOMBlobBuilder::AppendArrayBuffer(JSObject* aBuffer)
NS_IMETHODIMP
nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
nsIDOMBlob** aBlob)
{
return GetBlobInternal(aContentType, true, aBlob);
}
nsresult
nsDOMBlobBuilder::GetBlobInternal(const nsAString& aContentType,
bool aClearBuffer,
nsIDOMBlob** aBlob)
{
NS_ENSURE_ARG(aBlob);
@ -332,7 +246,9 @@ nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
// the existing contents of the BlobBuilder should be included
// in the next blob produced. This seems silly and has been raised
// on the WHATWG listserv.
mBlobs.Clear();
if (aClearBuffer) {
mBlobs.Clear();
}
return NS_OK;
}

View File

@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla File API.
*
* The Initial Developer of the Original Code is
* Kyle Huey <me@kylehuey.com>
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMBlobBuilder_h
#define nsDOMBlobBuilder_h
#include "nsDOMFile.h"
#include "CheckedInt.h"
#include "mozilla/StdInt.h"
using namespace mozilla;
class nsDOMMultipartFile : public nsDOMFileBase
{
public:
// Create as a file
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aName,
const nsAString& aContentType)
: nsDOMFileBase(aName, aContentType, UINT64_MAX),
mBlobs(aBlobs)
{
}
// Create as a blob
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aContentType)
: nsDOMFileBase(aContentType, UINT64_MAX),
mBlobs(aBlobs)
{
}
already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType);
NS_IMETHOD GetSize(PRUint64*);
NS_IMETHOD GetInternalStream(nsIInputStream**);
protected:
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
};
class nsDOMBlobBuilder : public nsIDOMMozBlobBuilder
{
public:
nsDOMBlobBuilder()
: mData(nsnull), mDataLen(0), mDataBufferLen(0)
{}
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZBLOBBUILDER
nsresult GetBlobInternal(const nsAString& aContentType,
bool aClearBuffer, nsIDOMBlob** aBlob);
nsresult AppendVoidPtr(const void* aData, PRUint32 aLength);
protected:
nsresult AppendString(JSString* aString, JSContext* aCx);
nsresult AppendBlob(nsIDOMBlob* aBlob);
nsresult AppendArrayBuffer(JSObject* aBuffer);
bool ExpandBufferSize(PRUint64 aSize)
{
if (mDataBufferLen >= mDataLen + aSize) {
mDataLen += aSize;
return true;
}
// Start at 1 or we'll loop forever.
CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1);
while (bufferLen.valid() && bufferLen.value() < mDataLen + aSize)
bufferLen *= 2;
if (!bufferLen.valid())
return false;
// PR_ memory functions are still fallible
void* data = PR_Realloc(mData, bufferLen.value());
if (!data)
return false;
mData = data;
mDataBufferLen = bufferLen.value();
mDataLen += aSize;
return true;
}
void Flush() {
if (mData) {
// If we have some data, create a blob for it
// and put it on the stack
nsCOMPtr<nsIDOMBlob> blob =
new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
mBlobs.AppendElement(blob);
mData = nsnull; // The nsDOMMemoryFile takes ownership of the buffer
mDataLen = 0;
mDataBufferLen = 0;
}
}
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
void* mData;
PRUint64 mDataLen;
PRUint64 mDataBufferLen;
};
#endif

View File

@ -1722,6 +1722,18 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsDocument,
nsNodeUtils::LastRelease(this))
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
return nsGenericElement::CanSkip(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
return nsGenericElement::CanSkipInCC(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument)
return nsGenericElement::CanSkipThis(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
static PLDHashOperator
SubDocTraverser(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number,
void *arg)
@ -5847,24 +5859,21 @@ nsDocument::SetTextContent(const nsAString & aTextContent)
NS_IMETHODIMP
nsDocument::LookupPrefix(const nsAString & namespaceURI, nsAString & aResult)
{
SetDOMStringToNull(aResult);
return NS_OK;
return nsINode::LookupPrefix(namespaceURI, aResult);
}
NS_IMETHODIMP
nsDocument::IsDefaultNamespace(const nsAString & namespaceURI,
bool *aResult)
{
*aResult = namespaceURI.IsEmpty();
return NS_OK;
return nsINode::IsDefaultNamespace(namespaceURI, aResult);
}
NS_IMETHODIMP
nsDocument::LookupNamespaceURI(const nsAString & prefix,
nsAString & aResult)
{
SetDOMStringToNull(aResult);
return NS_OK;
return nsINode::LookupNamespaceURI(prefix, aResult);
}
NS_IMETHODIMP

View File

@ -880,8 +880,8 @@ public:
MaybeRescheduleAnimationFrameNotifications();
}
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
nsIDocument)
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
nsIDocument)
void DoNotifyPossibleTitleChange();

View File

@ -97,6 +97,18 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericDOMDataNode)
nsINode::Trace(tmp, aCallback, aClosure);
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode)
return nsGenericElement::CanSkip(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode)
return nsGenericElement::CanSkipInCC(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode)
return nsGenericElement::CanSkipThis(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
// Always need to traverse script objects, so do that before we check
// if we're uncollectable.

View File

@ -272,7 +272,7 @@ public:
void ToCString(nsAString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
#endif
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsGenericDOMDataNode)
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericDOMDataNode)
protected:
virtual mozilla::dom::Element* GetNameSpaceElement()
@ -348,6 +348,16 @@ protected:
nsTextFragment mText;
public:
virtual bool IsPurple()
{
return mRefCnt.IsPurple();
}
virtual void RemovePurple()
{
mRefCnt.RemovePurple();
}
private:
already_AddRefed<nsIAtom> GetCurrentValueAtom();
};

View File

@ -153,7 +153,7 @@
#include "nsSVGFeatures.h"
#include "nsDOMMemoryReporter.h"
#include "nsWrapperCacheInlines.h"
#include "nsCycleCollector.h"
#include "xpcpublic.h"
#include "xpcprivate.h"
@ -1208,11 +1208,20 @@ nsINode::Trace(nsINode *tmp, TraceCallback cb, void *closure)
nsContentUtils::TraceWrapper(tmp, cb, closure);
}
static bool
IsXBL(nsINode* aNode)
static
bool UnoptimizableCCNode(nsINode* aNode)
{
return aNode->IsElement() &&
aNode->AsElement()->IsInNamespace(kNameSpaceID_XBL);
const PtrBits problematicFlags = (NODE_IS_ANONYMOUS |
NODE_IS_IN_ANONYMOUS_SUBTREE |
NODE_IS_NATIVE_ANONYMOUS_ROOT |
NODE_MAY_BE_IN_BINDING_MNGR |
NODE_IS_INSERTION_PARENT);
return aNode->HasFlag(problematicFlags) ||
aNode->NodeType() == nsIDOMNode::ATTRIBUTE_NODE ||
// For strange cases like xbl:content/xbl:children
(aNode->IsElement() &&
aNode->AsElement()->IsInNamespace(kNameSpaceID_XBL));
}
/* static */
@ -1227,18 +1236,11 @@ nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
if (nsCCUncollectableMarker::sGeneration) {
// If we're black no need to traverse.
if (tmp->IsBlack()) {
if (tmp->IsBlack() || tmp->InCCBlackTree()) {
return false;
}
const PtrBits problematicFlags =
(NODE_IS_ANONYMOUS |
NODE_IS_IN_ANONYMOUS_SUBTREE |
NODE_IS_NATIVE_ANONYMOUS_ROOT |
NODE_MAY_BE_IN_BINDING_MNGR |
NODE_IS_INSERTION_PARENT);
if (!tmp->HasFlag(problematicFlags) && !IsXBL(tmp)) {
if (!UnoptimizableCCNode(tmp)) {
// If we're in a black document, return early.
if ((currentDoc && currentDoc->IsBlack())) {
return false;
@ -1246,7 +1248,7 @@ nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
// If we're not in anonymous content and we have a black parent,
// return early.
nsIContent* parent = tmp->GetParent();
if (parent && !IsXBL(parent) && parent->IsBlack()) {
if (parent && !UnoptimizableCCNode(parent) && parent->IsBlack()) {
NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
return false;
}
@ -4256,6 +4258,382 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
nsINode::Trace(tmp, aCallback, aClosure);
NS_IMPL_CYCLE_COLLECTION_TRACE_END
static JSObject*
GetJSObjectChild(nsINode* aNode)
{
if (aNode->PreservingWrapper()) {
return aNode->GetWrapperPreserveColor();
}
return aNode->GetExpandoObjectPreserveColor();
}
static bool
NeedsScriptTraverse(nsINode* aNode)
{
JSObject* o = GetJSObjectChild(aNode);
return o && xpc_IsGrayGCThing(o);
}
void
nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
void* aData)
{
PRUint32* gen = static_cast<PRUint32*>(aData);
xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
}
void
nsGenericElement::MarkUserDataHandler(void* aObject, nsIAtom* aKey,
void* aChild, void* aData)
{
nsCOMPtr<nsIXPConnectWrappedJS> wjs =
do_QueryInterface(static_cast<nsISupports*>(aChild));
xpc_UnmarkGrayObject(wjs);
}
static void
MarkNodeChildren(nsINode* aNode)
{
JSObject* o = GetJSObjectChild(aNode);
xpc_UnmarkGrayObject(o);
nsEventListenerManager* elm = aNode->GetListenerManager(false);
if (elm) {
elm->UnmarkGrayJSListeners();
}
if (aNode->HasProperties()) {
nsIDocument* ownerDoc = aNode->OwnerDoc();
ownerDoc->PropertyTable(DOM_USER_DATA)->
Enumerate(aNode, nsGenericElement::MarkUserData,
&nsCCUncollectableMarker::sGeneration);
ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->
Enumerate(aNode, nsGenericElement::MarkUserDataHandler,
&nsCCUncollectableMarker::sGeneration);
}
}
nsINode*
FindOptimizableSubtreeRoot(nsINode* aNode)
{
nsINode* p;
while ((p = aNode->GetNodeParent())) {
if (UnoptimizableCCNode(aNode)) {
return nsnull;
}
aNode = p;
}
if (UnoptimizableCCNode(aNode)) {
return nsnull;
}
return aNode;
}
nsAutoTArray<nsINode*, 1020>* gCCBlackMarkedNodes = nsnull;
void
ClearBlackMarkedNodes()
{
if (!gCCBlackMarkedNodes) {
return;
}
PRUint32 len = gCCBlackMarkedNodes->Length();
for (PRUint32 i = 0; i < len; ++i) {
nsINode* n = gCCBlackMarkedNodes->ElementAt(i);
n->SetCCMarkedRoot(false);
n->SetInCCBlackTree(false);
}
delete gCCBlackMarkedNodes;
gCCBlackMarkedNodes = nsnull;
}
// static
bool
nsGenericElement::CanSkipInCC(nsINode* aNode)
{
// Don't try to optimize anything during shutdown.
if (nsCCUncollectableMarker::sGeneration == 0) {
return false;
}
// Bail out early if aNode is somewhere in anonymous content,
// or otherwise unusual.
if (UnoptimizableCCNode(aNode)) {
return false;
}
nsIDocument* currentDoc = aNode->GetCurrentDoc();
if (currentDoc &&
nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
return !NeedsScriptTraverse(aNode);
}
nsINode* root =
currentDoc ? static_cast<nsINode*>(currentDoc) :
FindOptimizableSubtreeRoot(aNode);
if (!root) {
return false;
}
// Subtree has been traversed already.
if (root->CCMarkedRoot()) {
return root->InCCBlackTree() && !NeedsScriptTraverse(aNode);
}
if (!gCCBlackMarkedNodes) {
gCCBlackMarkedNodes = new nsAutoTArray<nsINode*, 1020>;
}
// nodesToUnpurple contains nodes which will be removed
// from the purple buffer if the DOM tree is black.
nsAutoTArray<nsIContent*, 1020> nodesToUnpurple;
// grayNodes need script traverse, so they aren't removed from
// the purple buffer, but are marked to be in black subtree so that
// traverse is faster.
nsAutoTArray<nsINode*, 1020> grayNodes;
bool foundBlack = root->IsBlack();
if (root != currentDoc) {
currentDoc = nsnull;
if (NeedsScriptTraverse(root)) {
grayNodes.AppendElement(root);
} else if (static_cast<nsIContent*>(root)->IsPurple()) {
nodesToUnpurple.AppendElement(static_cast<nsIContent*>(root));
}
}
// Traverse the subtree and check if we could know without CC
// that it is black.
// Note, this traverse is non-virtual and inline, so it should be a lot faster
// than CC's generic traverse.
for (nsIContent* node = root->GetFirstChild(); node;
node = node->GetNextNode(root)) {
foundBlack = foundBlack || node->IsBlack();
if (foundBlack && currentDoc) {
// If we can mark the whole document black, no need to optimize
// so much, since when the next purple node in the document will be
// handled, it is fast to check that currentDoc is in CCGeneration.
break;
}
if (NeedsScriptTraverse(node)) {
// Gray nodes need real CC traverse.
grayNodes.AppendElement(node);
} else if (node->IsPurple()) {
nodesToUnpurple.AppendElement(node);
}
}
root->SetCCMarkedRoot(true);
root->SetInCCBlackTree(foundBlack);
gCCBlackMarkedNodes->AppendElement(root);
if (!foundBlack) {
return false;
}
if (currentDoc) {
// Special case documents. If we know the document is black,
// we can mark the document to be in CCGeneration.
currentDoc->
MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
} else {
for (PRUint32 i = 0; i < grayNodes.Length(); ++i) {
nsINode* node = grayNodes[i];
node->SetInCCBlackTree(true);
}
gCCBlackMarkedNodes->AppendElements(grayNodes);
}
// Subtree is black, we can remove non-gray purple nodes from
// purple buffer.
for (PRUint32 i = 0; i < nodesToUnpurple.Length(); ++i) {
nsIContent* purple = nodesToUnpurple[i];
// Can't remove currently handled purple node.
if (purple != aNode) {
purple->RemovePurple();
}
}
return !NeedsScriptTraverse(aNode);
}
nsAutoTArray<nsINode*, 1020>* gPurpleRoots = nsnull;
void ClearPurpleRoots()
{
if (!gPurpleRoots) {
return;
}
PRUint32 len = gPurpleRoots->Length();
for (PRUint32 i = 0; i < len; ++i) {
nsINode* n = gPurpleRoots->ElementAt(i);
n->SetIsPurpleRoot(false);
}
delete gPurpleRoots;
gPurpleRoots = nsnull;
}
static bool
ShouldClearPurple(nsIContent* aContent)
{
if (aContent && aContent->IsPurple()) {
return true;
}
JSObject* o = GetJSObjectChild(aContent);
if (o && xpc_IsGrayGCThing(o)) {
return true;
}
if (aContent->GetListenerManager(false)) {
return true;
}
return aContent->HasProperties();
}
// CanSkip checks if aNode is black, and if it is, returns
// true. If aNode is in a black DOM tree, CanSkip may also remove other objects
// from purple buffer and unmark event listeners and user data.
// If the root of the DOM tree is a document, less optimizations are done
// since checking the blackness of the current document is usually fast and we
// don't want slow down such common cases.
bool
nsGenericElement::CanSkip(nsINode* aNode)
{
// Don't try to optimize anything during shutdown.
if (nsCCUncollectableMarker::sGeneration == 0) {
return false;
}
// Bail out early if aNode is somewhere in anonymous content,
// or otherwise unusual.
if (UnoptimizableCCNode(aNode)) {
return false;
}
nsIDocument* currentDoc = aNode->GetCurrentDoc();
if (currentDoc &&
nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
MarkNodeChildren(aNode);
return true;
}
nsINode* root = currentDoc ? static_cast<nsINode*>(currentDoc) :
FindOptimizableSubtreeRoot(aNode);
if (!root) {
return false;
}
// Subtree has been traversed already, and aNode
// wasn't removed from purple buffer. No need to do more here.
if (root->IsPurpleRoot()) {
return false;
}
// nodesToClear contains nodes which are either purple or
// gray.
nsAutoTArray<nsIContent*, 1020> nodesToClear;
bool foundBlack = root->IsBlack();
if (root != currentDoc) {
currentDoc = nsnull;
if (ShouldClearPurple(static_cast<nsIContent*>(root))) {
nodesToClear.AppendElement(static_cast<nsIContent*>(root));
}
}
// Traverse the subtree and check if we could know without CC
// that it is black.
// Note, this traverse is non-virtual and inline, so it should be a lot faster
// than CC's generic traverse.
for (nsIContent* node = root->GetFirstChild(); node;
node = node->GetNextNode(root)) {
foundBlack = foundBlack || node->IsBlack();
if (foundBlack) {
if (currentDoc) {
// If we can mark the whole document black, no need to optimize
// so much, since when the next purple node in the document will be
// handled, it is fast to check that the currentDoc is in CCGeneration.
break;
}
// No need to put stuff to the nodesToClear array, if we can clear it
// already here.
if (node->IsPurple() && node != aNode) {
node->RemovePurple();
}
MarkNodeChildren(node);
} else if (ShouldClearPurple(node)) {
// Collect interesting nodes which we can clear if we find that
// they are kept alive in a black tree.
nodesToClear.AppendElement(node);
}
}
if (!foundBlack) {
if (!gPurpleRoots) {
gPurpleRoots = new nsAutoTArray<nsINode*, 1020>();
}
root->SetIsPurpleRoot(true);
gPurpleRoots->AppendElement(root);
return false;
}
if (currentDoc) {
// Special case documents. If we know the document is black,
// we can mark the document to be in CCGeneration.
currentDoc->
MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
MarkNodeChildren(currentDoc);
}
// Subtree is black, so we can remove purple nodes from
// purple buffer and mark stuff that to be certainly alive.
for (PRUint32 i = 0; i < nodesToClear.Length(); ++i) {
nsIContent* n = nodesToClear[i];
MarkNodeChildren(n);
// Can't remove currently handled purple node.
if (n != aNode && n->IsPurple()) {
n->RemovePurple();
}
}
return true;
}
bool
nsGenericElement::CanSkipThis(nsINode* aNode)
{
if (nsCCUncollectableMarker::sGeneration == 0) {
return false;
}
if (aNode->IsBlack()) {
return true;
}
nsIDocument* c = aNode->GetCurrentDoc();
return
((c && nsCCUncollectableMarker::InGeneration(c->GetMarkedCCGeneration())) ||
aNode->InCCBlackTree()) && !NeedsScriptTraverse(aNode);
}
void
nsGenericElement::InitCCCallbacks()
{
nsCycleCollector_setForgetSkippableCallback(ClearPurpleRoots);
nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes);
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericElement)
return nsGenericElement::CanSkip(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericElement)
return nsGenericElement::CanSkipInCC(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericElement)
return nsGenericElement::CanSkipThis(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
static const char* kNSURIs[] = {
" ([none])",
" (xmlns)",

View File

@ -602,7 +602,7 @@ public:
*/
virtual nsAttrInfo GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const;
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsGenericElement)
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericElement)
virtual void NodeInfoChanged(nsINodeInfo* aOldNodeInfo)
{
@ -613,6 +613,24 @@ public:
*/
void FireNodeRemovedForChildren();
virtual bool IsPurple()
{
return mRefCnt.IsPurple();
}
virtual void RemovePurple()
{
mRefCnt.RemovePurple();
}
static bool CanSkip(nsINode* aNode);
static bool CanSkipInCC(nsINode* aNode);
static bool CanSkipThis(nsINode* aNode);
static void InitCCCallbacks();
static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
void *aData);
static void MarkUserDataHandler(void* aObject, nsIAtom* aKey, void* aChild,
void* aData);
protected:
/**
* Set attribute and (if needed) notify documentobservers and fire off

View File

@ -582,6 +582,8 @@ nsXMLHttpRequest::ResetResponse()
mResponseBody.Truncate();
mResponseText.Truncate();
mResponseBlob = nsnull;
mDOMFile = nsnull;
mBuilder = nsnull;
mResultArrayBuffer = nsnull;
mResultJSON = JSVAL_VOID;
mLoadTransferred = 0;
@ -967,6 +969,28 @@ nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
return NS_OK;
}
nsresult
nsXMLHttpRequest::CreatePartialBlob()
{
if (mDOMFile) {
if (mLoadTotal == mLoadTransferred) {
mResponseBlob = mDOMFile;
} else {
mResponseBlob =
mDOMFile->CreateSlice(0, mLoadTransferred, EmptyString());
}
return NS_OK;
}
nsCAutoString contentType;
if (mLoadTotal == mLoadTransferred) {
mChannel->GetContentType(contentType);
}
return mBuilder->GetBlobInternal(NS_ConvertASCIItoUTF16(contentType),
false, getter_AddRefs(mResponseBlob));
}
/* attribute AString responseType; */
NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
{
@ -995,6 +1019,9 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
aResponseType.AssignLiteral("moz-chunked-arraybuffer");
break;
case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB:
aResponseType.AssignLiteral("moz-blob");
break;
default:
NS_ERROR("Should not happen");
}
@ -1041,6 +1068,8 @@ NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER;
} else if (aResponseType.EqualsLiteral("moz-blob")) {
mResponseType = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB;
}
// If the given value is not the empty string, "arraybuffer",
// "blob", "document", or "text" terminate these steps.
@ -1053,7 +1082,8 @@ NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
if (mState & XML_HTTP_REQUEST_HEADERS_RECEIVED) {
nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(mChannel));
if (cc) {
cc->SetCacheAsFile(mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB);
cc->SetCacheAsFile(mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB);
}
}
@ -1097,12 +1127,22 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponse(JSContext *aCx, jsval *aResult)
break;
case XML_HTTP_RESPONSE_TYPE_BLOB:
if (mState & XML_HTTP_REQUEST_DONE && mResponseBlob) {
case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB:
*aResult = JSVAL_NULL;
if (mState & XML_HTTP_REQUEST_DONE) {
// do nothing here
} else if (mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
if (!mResponseBlob) {
rv = CreatePartialBlob();
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
return rv;
}
if (mResponseBlob) {
JSObject* scope = JS_GetGlobalForScopeChain(aCx);
rv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, aResult,
nsnull, true);
} else {
*aResult = JSVAL_NULL;
}
break;
@ -1712,16 +1752,29 @@ nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
return NS_ERROR_FAILURE;
}
if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB &&
xmlHttpRequest->mResponseBlob) {
*writeCount = count;
return NS_OK;
nsresult rv = NS_OK;
if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
if (!xmlHttpRequest->mDOMFile) {
if (!xmlHttpRequest->mBuilder) {
xmlHttpRequest->mBuilder = new nsDOMBlobBuilder();
}
rv = xmlHttpRequest->mBuilder->AppendVoidPtr(fromRawSegment, count);
}
// Clear the cache so that the blob size is updated.
if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
xmlHttpRequest->mResponseBlob = nsnull;
}
if (NS_SUCCEEDED(rv)) {
*writeCount = count;
}
return rv;
}
if ((xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT &&
xmlHttpRequest->mResponseXML) ||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
// Copy for our own use
PRUint32 previousLength = xmlHttpRequest->mResponseBody.Length();
@ -1738,8 +1791,6 @@ nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
}
nsresult rv = NS_OK;
if (xmlHttpRequest->mState & XML_HTTP_REQUEST_PARSEBODY) {
// Give the same data to the parser.
@ -1773,7 +1824,7 @@ nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
return rv;
}
bool nsXMLHttpRequest::CreateResponseBlob(nsIRequest *request)
bool nsXMLHttpRequest::CreateDOMFile(nsIRequest *request)
{
nsCOMPtr<nsIFile> file;
nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(request));
@ -1801,9 +1852,10 @@ bool nsXMLHttpRequest::CreateResponseBlob(nsIRequest *request)
fromFile = true;
}
mResponseBlob =
mDOMFile =
new nsDOMFileFile(file, NS_ConvertASCIItoUTF16(contentType), cacheToken);
mResponseBody.Truncate();
mBuilder = nsnull;
NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
}
return fromFile;
}
@ -1822,8 +1874,9 @@ nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
mProgressSinceLastProgressEvent = true;
bool cancelable = false;
if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB && !mResponseBlob) {
cancelable = CreateResponseBlob(request);
if ((mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMFile) {
cancelable = CreateDOMFile(request);
// The nsIStreamListener contract mandates us
// to read from the stream before returning.
}
@ -1835,7 +1888,7 @@ nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
if (cancelable) {
// We don't have to read from the local file for the blob response
mResponseBlob->GetSize(&mLoadTransferred);
mDOMFile->GetSize(&mLoadTransferred);
ChangeState(XML_HTTP_REQUEST_LOADING);
return request->Cancel(NS_OK);
}
@ -1936,7 +1989,8 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB) {
if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(mChannel));
if (cc) {
cc->SetCacheAsFile(true);
@ -2132,34 +2186,31 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
MaybeDispatchProgressEvents(true);
}
nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
if (NS_SUCCEEDED(status) && mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB) {
if (!mResponseBlob) {
CreateResponseBlob(request);
if (NS_SUCCEEDED(status) &&
(mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB)) {
if (!mDOMFile) {
CreateDOMFile(request);
}
if (!mResponseBlob) {
if (mDOMFile) {
mResponseBlob = mDOMFile;
mDOMFile = nsnull;
} else {
// Smaller files may be written in cache map instead of separate files.
// Also, no-store response cannot be written in persistent cache.
nsCAutoString contentType;
mChannel->GetContentType(contentType);
// XXX We should change mResponseBody to be a raw malloc'ed buffer
// to avoid copying the data.
PRUint32 blobLen = mResponseBody.Length();
void *blobData = PR_Malloc(blobLen);
if (blobData) {
memcpy(blobData, mResponseBody.BeginReading(), blobLen);
mResponseBlob =
new nsDOMMemoryFile(blobData, blobLen,
NS_ConvertASCIItoUTF16(contentType));
mResponseBody.Truncate();
}
NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
mBuilder->GetBlobInternal(NS_ConvertASCIItoUTF16(contentType),
false, getter_AddRefs(mResponseBlob));
mBuilder = nsnull;
}
NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
}
nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
channel->SetNotificationCallbacks(nsnull);
mNotificationCallbacks = nsnull;
mChannelEventSink = nsnull;

View File

@ -65,6 +65,8 @@
#include "nsDOMProgressEvent.h"
#include "nsDOMEventTargetWrapperCache.h"
#include "nsContentUtils.h"
#include "nsDOMFile.h"
#include "nsDOMBlobBuilder.h"
class nsILoadGroup;
class AsyncVerifyRedirectCallbackForwarder;
@ -217,7 +219,8 @@ protected:
PRUint32 count,
PRUint32 *writeCount);
nsresult CreateResponseParsedJSON(JSContext* aCx);
bool CreateResponseBlob(nsIRequest *request);
nsresult CreatePartialBlob(void);
bool CreateDOMFile(nsIRequest *request);
// Change the state of the object with this. The broadcast argument
// determines if the onreadystatechange listener should be called.
nsresult ChangeState(PRUint32 aState, bool aBroadcast = true);
@ -309,10 +312,20 @@ protected:
XML_HTTP_RESPONSE_TYPE_TEXT,
XML_HTTP_RESPONSE_TYPE_JSON,
XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT,
XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER
XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER,
XML_HTTP_RESPONSE_TYPE_MOZ_BLOB
} mResponseType;
// It is either a cached blob-response from the last call to GetResponse,
// but is also explicitly set in OnStopRequest.
nsCOMPtr<nsIDOMBlob> mResponseBlob;
// Non-null only when we are able to get a os-file representation of the
// response, i.e. when loading from a file, or when the http-stream
// caches into a file or is reading from a cached file.
nsRefPtr<nsDOMFileBase> mDOMFile;
// We stream data to mBuilder when response type is "blob" or "moz-blob"
// and mDOMFile is null.
nsRefPtr<nsDOMBlobBuilder> mBuilder;
nsCString mOverrideMimeType;

View File

@ -529,6 +529,7 @@ _TEST_FILES2 = \
file_bug692434.xml \
test_bug693615.html \
test_bug693875.html \
test_bug694754.xhtml \
test_bug698384.html \
test_nodelist_holes.html \
test_xhr_abort_after_load.html \

View File

@ -212,13 +212,16 @@ is(xhr.response, null, "Bad JSON should result in null response even 2nd time.")
// test response (responseType='blob')
var onloadCount = 0;
function checkOnloadCount() {
if (++onloadCount >= 3) SimpleTest.finish();
if (++onloadCount >= 6) SimpleTest.finish();
};
var responseTypes = ['blob', 'moz-blob'];
for (var i = 0; i < responseTypes.length; i++) {
var t = responseTypes[i];
// with a simple text file
xhr = new XMLHttpRequest();
xhr.open("GET", 'file_XHR_pass2.txt');
xhr.responseType = 'blob';
xhr.responseType = t;
xhr.onloadend = continueTest;
xhr.send(null);
yield;
@ -245,7 +248,7 @@ xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 2:
is(xhr.status, 200, "wrong status");
xhr.responseType = 'blob';
xhr.responseType = t;
break;
case 4:
b = xhr.response;
@ -293,9 +296,10 @@ xhr.onreadystatechange = function() {
}
};
xhr.open("GET", 'file_XHR_binary2.bin', true);
xhr.responseType = 'blob';
xhr.responseType = t;
xhr.send(null);
})();
}
var client = new XMLHttpRequest();
client.onreadystatechange = function() {

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:test="http://example.com/test">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=694754
-->
<head>
<title>Test for Bug 694754</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=694754">Mozilla Bug 694754</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 694754 **/
/*
The following code tests if calling the DOM methods Document::lookupNamespaceURI
and Document::lookupPrefix directly (with quickstubs) and through XPCOM leads
to the same result.
This test makes use of the bug/feature that deleting a method from the
prototype forces the engine to go through XPCOM.
*/
// Document::lookupPrefix called directly (quickstubs)
var prefixDirect = document.lookupPrefix("http://example.com/test");
is(prefixDirect, "test",
"calling Document::lookupPrefix through quickstubs works");
// Document::lookupPrefix called via XPCOM
var proto = Object.getPrototypeOf(document);
delete(proto.lookupPrefix);
var prefixThroughXPCOM = document.lookupPrefix("http://example.com/test");
is(prefixThroughXPCOM, "test",
"calling Document::lookupPrefix through XPCOM works");
// Document::lookupNamespaceURI called directly (quickstubs)
var namespaceDirect = document.lookupNamespaceURI(null);
is(namespaceDirect, "http://www.w3.org/1999/xhtml",
"calling Document::lookupNamespaceURI through quickstubs works");
// Document::lookupNamespaceURI called via XPCOM
delete(proto.lookupNamespaceURI);
var namespaceThroughXPCOM = document.lookupNamespaceURI(null);
is(namespaceThroughXPCOM, "http://www.w3.org/1999/xhtml",
"calling Document::lookupNamespaceURI through XPCOM works");
// Document::isDefaultNamespace called directly (quickstubs)
var isDefaultNamespaceDirect = document.isDefaultNamespace("http://www.w3.org/1999/xhtml");
is(isDefaultNamespaceDirect, true,
"Default namespace correctly detected through quickstubs");
// Document::isDefaultNamespace called via XPCOM
delete(proto.isDefaultNamespace);
var isDefaultNamespaceXPCOM = document.isDefaultNamespace("http://www.w3.org/1999/xhtml");
is(isDefaultNamespaceXPCOM, true,
"Default namespace correctly detected through XPCOM");
</script>
</pre>
</body>
</html>

View File

@ -39,13 +39,21 @@ function updateProgress(e, data, testName) {
is(typeof e.target.response, "string", "response should be a string" + test);
response = e.target.response;
}
else if (data.blob) {
ok(e.target.response instanceof Blob, "response should be a Blob" + test);
response = e.target.response;
}
else {
ok(e.target.response instanceof ArrayBuffer, "response should be a ArrayBuffer" + test);
ok(e.target.response instanceof ArrayBuffer, "response should be an ArrayBuffer" + test);
response = bufferToString(e.target.response);
}
is(e.target.response, e.target.response, "reflexivity should hold" + test);
if (!data.nodata && !data.encoded) {
if (!data.chunked) {
if (data.blob) {
is(e.loaded, response.size, "event.loaded matches response size" + test);
}
else if (!data.chunked) {
is(e.loaded, response.length, "event.loaded matches response size" + test);
}
else {
@ -57,7 +65,7 @@ function updateProgress(e, data, testName) {
ok(e.loaded - data.receivedBytes <= data.pendingBytes,
"event.loaded didn't increase too much" + test);
if (!data.nodata) {
if (!data.nodata && !data.blob) {
var newData;
ok(startsWith(response, data.receivedResult),
"response strictly grew" + test);
@ -74,7 +82,7 @@ function updateProgress(e, data, testName) {
is(e.total, data.total, "total" + test);
}
if (!data.nodata) {
if (!data.nodata && !data.blob) {
data.pendingResult = data.pendingResult.substr(newData.length);
}
data.pendingBytes -= e.loaded - data.receivedBytes;
@ -113,7 +121,8 @@ function runTests() {
var responseTypes = [{ type: "text", text: true },
{ type: "arraybuffer", text: false, nodata: true },
{ type: "blob", text: false, nodata: true },
{ type: "blob", text: false, nodata: true, blob: true },
{ type: "moz-blob", text: false, nodata: false, blob: true },
{ type: "document", text: true, nodata: true },
{ type: "json", text: true, nodata: true },
{ type: "", text: true },
@ -153,7 +162,7 @@ function runTests() {
{ data: utf8encode("a\u867Eb").substr(4), utf16: "b" },
{ close: true },
];
if (responseType.type === "blob") {
if (responseType.blob) {
tests.push({ file: "file_XHR_binary2.bin", name: "cacheable data", total: 65536 },
{ close: true },
{ file: "file_XHR_binary2.bin", name: "cached data", total: 65536 },
@ -177,6 +186,7 @@ function runTests() {
nodata: responseType.nodata,
chunked: responseType.chunked,
text: responseType.text,
blob: responseType.blob,
file: test.file };
xhr.onreadystatechange = null;
@ -235,7 +245,7 @@ function runTests() {
is(xhr.response, null, "chunked data has null response for " + testState.name);
}
if (!testState.nodata || responseType.chunked) {
if (!testState.nodata && !responseType.blob || responseType.chunked) {
// This branch intentionally left blank
// Under these conditions we check the response during updateProgress
}
@ -243,7 +253,7 @@ function runTests() {
is(bufferToString(xhr.response), testState.pendingResult,
"full response for " + testState.name);
}
else if (responseType.type === "blob") {
else if (responseType.blob) {
let reader = new FileReader;
reader.readAsBinaryString(xhr.response);
reader.onloadend = getEvent;
@ -280,7 +290,7 @@ function runTests() {
}
}
if (!testState.nodata) {
if (!testState.nodata && !testState.blob) {
is(testState.pendingResult, "",
"should have consumed the expected result");
}

View File

@ -995,7 +995,7 @@ NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
!Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
return NS_ERROR_NOT_AVAILABLE;
}
#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(XP_LINUX)
#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(LINUX)
return NS_ERROR_NOT_AVAILABLE;
#endif

View File

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

View File

@ -27,7 +27,7 @@ var array = new ArrayBuffer(128);
shouldBeNonNull("array");
var buf = gl.createBuffer();
shouldBeNonNull(buf);
shouldBeNonNull("buf");
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
glErrorShouldBe(gl, gl.INVALID_OPERATION);

View File

@ -102,7 +102,7 @@ if (!gl) {
testPassed("context exists");
gl.program = createProgram(gl, "vshader", "fshader", ["vPosition"]);
shouldBeNonNull(gl.program);
shouldBeNonNull("gl.program");
gl.useProgram(gl.program);
gl.enable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);

View File

@ -101,7 +101,7 @@ if (!gl) {
testPassed("context exists");
gl.program = createProgram(gl, "vshader", "fshader", ["vPosition"]);
shouldBeNonNull(gl.program);
shouldBeNonNull("gl.program");
gl.useProgram(gl.program);
gl.enable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);

View File

@ -1,7 +1,6 @@
<!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>
@ -68,7 +67,7 @@ function testLosingContext()
// we didn't call prevent default so we should not be able to restore the context
shouldGenerateGLError(gl, gl.INVALID_OPERATION, "extension.restoreContext()");
testLosingAndRestoringContext();
}, 1);
}, 0);
});
canvas.addEventListener("webglcontextrestored", testShouldNotRestoreContext);
allowRestore = false;
@ -106,7 +105,7 @@ function testLosingAndRestoringContext()
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);
}, 0);
});
canvas.addEventListener("webglcontextrestored", function() {
testRestoredContext();
@ -164,7 +163,7 @@ function testLostContext(e)
shouldBeTrue("gl.isContextLost()");
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
if (allowRestore)
if (allowRestore)
e.preventDefault();
}

View File

@ -1,7 +1,6 @@
<!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>

View File

@ -3,6 +3,5 @@ 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
--min-version 1.0.2 webgl-experimental-compressed-textures.html

View File

@ -57,7 +57,15 @@ void main() {
gl_FragColor = vec4(dx, dy, w, 1.0);
}
</script>
<!-- Shaders to link with test fragment shaders -->
<script id="goodVertexShader" type="x-shader/x-vertex">
attribute vec4 vPosition;
varying vec2 texCoord;
void main() {
texCoord = vPosition.xy;
gl_Position = vPosition;
}
</script>
<!-- Shaders to test output -->
<script id="outputVertexShader" type="x-shader/x-vertex">
attribute vec4 vPosition;
@ -183,19 +191,20 @@ function runHintTestEnabled() {
}
function runShaderTests(extensionEnabled) {
debug("");
debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
// Expect the macro shader to succeed ONLY if enabled
var macroFragmentShader = wtu.loadShaderFromScript(gl, "macroFragmentShader");
var macroFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "macroFragmentShader");
if (extensionEnabled) {
if (macroFragmentShader) {
if (macroFragmentProgram) {
// Expected result
testPassed("GL_OES_standard_derivatives defined in shaders when extension is enabled");
} else {
testFailed("GL_OES_standard_derivatives not defined in shaders when extension is enabled");
}
} else {
if (macroFragmentShader) {
if (macroFragmentProgram) {
testFailed("GL_OES_standard_derivatives defined in shaders when extension is disabled");
} else {
testPassed("GL_OES_standard_derivatives not defined in shaders when extension disabled");
@ -203,23 +212,23 @@ function runShaderTests(extensionEnabled) {
}
// Always expect the shader missing the #pragma to fail (whether enabled or not)
var missingPragmaFragmentShader = wtu.loadShaderFromScript(gl, "missingPragmaFragmentShader");
if (missingPragmaFragmentShader) {
var missingPragmaFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "missingPragmaFragmentShader");
if (missingPragmaFragmentProgram) {
testFailed("Shader built-ins allowed without #extension pragma");
} else {
testPassed("Shader built-ins disallowed without #extension pragma");
}
// Try to compile a shader using the built-ins that should only succeed if enabled
var testFragmentShader = wtu.loadShaderFromScript(gl, "testFragmentShader");
var testFragmentProgram = wtu.loadProgramFromScriptExpectError(gl, "goodVertexShader", "testFragmentShader");
if (extensionEnabled) {
if (testFragmentShader) {
if (testFragmentProgram) {
testPassed("Shader built-ins compiled successfully when extension enabled");
} else {
testFailed("Shader built-ins failed to compile when extension enabled");
}
} else {
if (testFragmentShader) {
if (testFragmentProgram) {
testFailed("Shader built-ins compiled successfully when extension disabled");
} else {
testPassed("Shader built-ins failed to compile when extension disabled");

View File

@ -1,10 +1,8 @@
functions/00_test_list.txt
implicit/00_test_list.txt
# commented out for version 1.0.1 of the conforamnce tests.
#matrices/00_test_list.txt
--min-version 1.0.2 matrices/00_test_list.txt
misc/00_test_list.txt
reserved/00_test_list.txt
# commented out for version 1.0.1 of the conforamnce tests.
#samplers/00_test_list.txt
--min-version 1.0.2 samplers/00_test_list.txt
variables/00_test_list.txt

View File

@ -1,10 +1,12 @@
attrib-location-length-limits.html
embedded-struct-definitions-forbidden.html
#glsl-2types-of-textures-on-same-unit.html
# this test is intentionally disabled as it is too strict and to hard to simulate
# glsl-2types-of-textures-on-same-unit.html
glsl-function-nodes.html
glsl-long-variable-names.html
non-ascii-comments.vert.html
non-ascii.vert.html
shader-with-256-character-identifier.frag.html
shader-with-257-character-identifier.frag.html
shader-with-_webgl-identifier.vert.html
@ -13,16 +15,22 @@ shader-with-arbitrary-indexing.vert.html
shader-with-attrib-array.vert.html
shader-with-attrib-struct.vert.html
shader-with-clipvertex.vert.html
--min-version 1.0.2 shader-with-conditional-scoping.html
shader-with-default-precision.frag.html
shader-with-default-precision.vert.html
shader-with-define-line-continuation.frag.html
shader-with-dfdx-no-ext.frag.html
shader-with-dfdx.frag.html
--min-version 1.0.2 shader-with-do-scoping.html
shader-with-error-directive.html
shader-with-explicit-int-cast.vert.html
shader-with-float-return-value.frag.html
--min-version 1.0.2 shader-with-for-scoping.html
--min-version 1.0.2 shader-with-for-loop.html
shader-with-frag-depth.frag.html
shader-with-function-recursion.frag.html
--min-version 1.0.2 shader-with-function-scoped-struct.html
--min-version 1.0.2 shader-with-functional-scoping.html
shader-with-glcolor.vert.html
shader-with-gles-1.frag.html
shader-with-gles-symbol.frag.html
@ -35,7 +43,10 @@ shader-with-ivec2-return-value.frag.html
shader-with-ivec3-return-value.frag.html
shader-with-ivec4-return-value.frag.html
shader-with-limited-indexing.frag.html
shader-with-line-directive.html
# we can not check line directives because GLSL 1.0.17 says error messages
# are implementation defined.
#shader-with-line-directive.html
--min-version 1.0.2 shader-with-hex-int-constant-macro.html
shader-with-long-line.html
shader-with-non-ascii-error.frag.html
shader-with-precision.frag.html
@ -45,6 +56,7 @@ shader-with-uniform-in-loop-condition.vert.html
shader-with-vec2-return-value.frag.html
shader-with-vec3-return-value.frag.html
shader-with-vec4-return-value.frag.html
--min-version 1.0.2 shader-with-vec4-vec3-vec4-conditional.html
shader-with-version-100.frag.html
shader-with-version-100.vert.html
shader-with-version-120.vert.html

View File

@ -60,8 +60,8 @@ if (attribLoc == -1) {
wtu.glErrorShouldBe(gl, gl.NONE);
debug("Test attrib location over the length limit");
debug("Shader compilation should fail");
shouldBe('wtu.loadShaderFromScript(gl, "badVertexShader", gl.VERTEX_SHADER, function (err) {})', 'null');
debug("Shader compilation or link should fail");
shouldBe('wtu.loadProgramFromScriptExpectError(gl, "badVertexShader", "fragmentShader")', 'null');
wtu.glErrorShouldBe(gl, gl.NONE);
debug("Attempt to bind too-long attrib location should produce error");

View File

@ -13,31 +13,184 @@
</canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456;
varying float alpha01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
<script id="vshader_shared_uniform" type="x-shader/x-vertex">
attribute vec3 vPosition;
uniform float value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
void main()
{
alpha01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 = 1.0;
gl_Position = vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456;
gl_Position = vec4(vPosition, value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
<script id="fshader_shared_uniform" type="x-shader/x-fragment">
precision mediump float;
varying float alpha01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
uniform float color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[3];
uniform float value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
void main()
{
gl_FragColor = vec4(1.0, 0.0, value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 1.0);
}
</script>
<script id="vshader_uniform_array" type="x-shader/x-vertex">
attribute vec3 vPosition;
void main()
{
gl_Position = vec4(vPosition, 1.0);
}
</script>
<script id="fshader_uniform_array" type="x-shader/x-fragment">
precision mediump float;
uniform float color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[2];
void main()
{
gl_FragColor = vec4(color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0], color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[1], 1.0, 1.0);
}
</script>
<script id="vshader_varying" type="x-shader/x-vertex">
attribute vec3 vPosition;
varying float value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
void main()
{
value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 = 1.0;
gl_Position = vec4(vPosition, 1.0);
}
</script>
<script id="fshader_varying" type="x-shader/x-fragment">
precision mediump float;
varying float value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
void main()
{
gl_FragColor = vec4(value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890, 0.0, 1.0, 1.0);
}
</script>
<script id="vshader_local" type="x-shader/x-vertex">
attribute vec3 vPosition;
void main()
{
for (int i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 = 0; i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 < 1; ++i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234)
{
gl_FragColor = vec4(color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0], color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[1], color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[2], alpha01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890);
gl_Position = vec4(vPosition, 1.0);
}
}
</script>
<script id="fshader_local" type="x-shader/x-fragment">
precision mediump float;
void main()
{
for (int i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 = 0; i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 < 1; ++i012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234)
{
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
}
}
</script>
<script id="vshader_attrib" type="x-shader/x-vertex">
attribute vec3 vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456;
void main()
{
gl_Position = vec4(vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456, 1.0);
}
</script>
<script id="fshader_attrib" type="x-shader/x-fragment">
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
}
</script>
<script>
function fail(x,y, buf, shouldBe)
if (window.initNonKhronosFramework) {
window.initNonKhronosFramework(false);
}
description("Verify that shader long variable names works fine if they are within 256 characters.");
debug("Test same long uniform name in both vertex shader and fragment shader");
var gl = initWebGL("example", "vshader_shared_uniform", "fshader_shared_uniform", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull("prog");
var valueLoc = gl.getUniformLocation(prog, "value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
shouldBeNonNull("valueLoc");
shouldBe("gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS)", "1");
var activeUniform = gl.getActiveUniform(prog, 0);
shouldBeNonNull("activeUniform");
shouldBe("activeUniform.type", "gl.FLOAT");
shouldBe("activeUniform.size", "1");
shouldBe("activeUniform.name", "'value01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'");
gl.uniform1f(valueLoc, 1.0);
drawAndCheckPixels(gl);
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
debug("Test long uniform array name");
var gl = initWebGL("example", "vshader_uniform_array", "fshader_uniform_array", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull("prog");
var redLoc = gl.getUniformLocation(prog, "color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0]");
shouldBeNonNull("redLoc");
var greenLoc = gl.getUniformLocation(prog, "color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[1]");
shouldBeNonNull("greenLoc");
shouldBe("gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS)", "1");
var activeUniform = gl.getActiveUniform(prog, 0);
shouldBeNonNull("activeUniform");
shouldBe("activeUniform.type", "gl.FLOAT");
shouldBe("activeUniform.size", "2");
shouldBe("activeUniform.name", "'color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0]'");
gl.uniform1f(redLoc, 1.0);
gl.uniform1f(greenLoc, 0.0);
drawAndCheckPixels(gl);
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
debug("Test long varying name");
var gl = initWebGL("example", "vshader_varying", "fshader_varying", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull("prog");
drawAndCheckPixels(gl);
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
debug("Test long local variable name");
var gl = initWebGL("example", "vshader_varying", "fshader_varying", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull("prog");
drawAndCheckPixels(gl);
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
debug("Test long attribute name");
var gl = initWebGL("example", "vshader_attrib", "fshader_attrib", [ "vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull("prog");
shouldBe("gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES)", "1");
var activeAttrib = gl.getActiveAttrib(prog, 0);
shouldBeNonNull("activeAttrib");
shouldBe("activeAttrib.size", "1");
shouldBe("activeAttrib.type", "gl.FLOAT_VEC3");
shouldBe("activeAttrib.name", "'vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456'");
drawAndCheckPixels(gl);
shouldBe("gl.getError()", "gl.NO_ERROR");
debug("");
function fail(x, y, buf, shouldBe)
{
var i = (y*50+x) * 4;
var reason = "pixel at ("+x+","+y+") is ("+buf[i]+","+buf[i+1]+","+buf[i+2]+","+buf[i+3]+"), should be "+shouldBe;
@ -49,56 +202,20 @@
testPassed("drawing is correct");
}
if (window.initNonKhronosFramework) {
window.initNonKhronosFramework(false);
}
description("Verify that shader long variable names works fine if they are within 256 characters.");
gl = initWebGL("example", "vshader", "fshader", [ "vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"], [ 0, 0, 0, 1 ], 1);
var prog = gl.getParameter(gl.CURRENT_PROGRAM);
shouldBeNonNull(prog);
var redLoc = gl.getUniformLocation(prog, "color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0]");
shouldBeNonNull(redLoc);
var greenLoc = gl.getUniformLocation(prog, "color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[1]");
shouldBeNonNull(greenLoc);
var blueLoc = gl.getUniformLocation(prog, "color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[2]");
shouldBeNonNull(blueLoc);
shouldBe("gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES)", "1");
var activeAttrib = gl.getActiveAttrib(prog, 0);
shouldBeNonNull(activeAttrib);
shouldBe("activeAttrib.size", "1");
shouldBe("activeAttrib.type", "gl.FLOAT_VEC4");
shouldBe("activeAttrib.name", "'vPosition0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456'");
shouldBe("gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS)", "1");
var activeUniform = gl.getActiveUniform(prog, 0);
shouldBeNonNull(activeUniform);
shouldBe("activeUniform.size", "3");
shouldBe("activeUniform.type", "gl.FLOAT");
shouldBe("activeUniform.name", "'color01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567[0]'");
gl.uniform1f(redLoc, 1.0);
gl.uniform1f(greenLoc, 0.0);
gl.uniform1f(blueLoc, 1.0);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
var buf = new Uint8Array(50 * 50 * 4);
gl.readPixels(0, 0, 50, 50, gl.RGBA, gl.UNSIGNED_BYTE, buf);
shouldBe("gl.getError()", "gl.NO_ERROR");
function checkPixels()
function drawAndCheckPixels(gl)
{
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
var buf = new Uint8Array(50 * 50 * 4);
gl.readPixels(0, 0, 50, 50, gl.RGBA, gl.UNSIGNED_BYTE, buf);
// Test several locations
// First line should be all black
for (var i = 0; i < 50; ++i)
@ -107,7 +224,7 @@
return;
}
// Line 15 should be red for at least 10 red pixels starting 20 pixels in
// Line 15 should be magenta for at least 10 pixels starting 20 pixels in
var offset = (15*50+20) * 4;
for (var i = 0; i < 10; ++i)
if (buf[offset+i*4] != 255 || buf[offset+i*4+1] != 0 || buf[offset+i*4+2] != 255 || buf[offset+i*4+3] != 255) {
@ -124,7 +241,7 @@
pass();
}
checkPixels();
successfullyParsed = true;
</script>
<script src="../../../resources/js-test-post.js"></script>

View File

@ -0,0 +1,47 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with conditional scoping should succeed
precision mediump float;
void main() {
int k = 3;
if (true) int g = k = 4;
else int q = k = 5;
g = 3;
q = 4;
if (true) int g = 4;
else int k = 10;
if (true) { int g = 10; }
else { int k = 20; }
gl_FragColor = vec4(1.);
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with do scoping should succeed
precision mediump float;
void main() {
int k = 0;
do int k = 1; while (k != 0); // ok, do always introduces scope
gl_FragColor = vec4(float(k));
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -33,10 +33,12 @@ GLSLConformanceTester.runTests([
vShaderSuccess: true,
fShaderId: 'fshaderWithErrorDirective',
fShaderSuccess: false,
fShaderTest: (function() {
return wtu.getLastError().indexOf("testing123 testing123") >= 0; }),
// We can't test for the actual error message as
// GLSL 1.0.17 11 says the messages are implementation dependant.
//fShaderTest: (function() {
// return wtu.getLastError().indexOf("testing123 testing123") >= 0; }),
linkSuccess: false,
passMsg: "error directive returns error user's error message",
passMsg: "error directive causes error",
},
]);

View File

@ -0,0 +1,81 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with for loop should succeed
// TODO(gman): trim to min size to test bug.
precision highp float;
uniform float time;
uniform vec2 resolution;
// Saw-tooth function that is synced with the demo music (128bpm)
float gBeat=fract(time*3.2/3.);
// Calculate the surface color
vec3 surfColor(vec2 p)
{
vec2 q=vec2(sin(.08*p.x),4.*p.y);
vec3 c=vec3(0);
for(float i=0.;i<15.;i++)
c+=(1.+sin(i*sin(time)+vec3(0.,1.3,2.2)))*.2/length(q-vec2(sin(i),12.*sin(.3*time+i)));
return c+vec3(mix(mod(floor(p.x*.2)+floor(p.y*2.2),2.),.2,gBeat));
}
// Ray trace (cylinder)
vec3 trace(vec3 o,vec3 d)
{
d.y*=.65+.1*sin(.5*time);
float D=1./(d.y*d.y+d.z*d.z),
a=(o.y*d.y+o.z*d.z)*D,
b=(o.y*o.y+o.z*o.z-36.)*D,
t=-a-sqrt(a*a-b);
o+=t*d;
return surfColor(vec2(o.x,atan(o.y,o.z)))*(1.+.01*t);
}
void main()
{
// Screen setup
vec2 p=(2.*gl_FragCoord.xy-resolution)/resolution.y,
q=2.*gl_FragCoord.xy/resolution-1.;
// Camera setup
vec3 cp=vec3(-time*20.+1.,1.6*sin(time*1.2),2.+2.*cos(time*.3)),
ct=cp+vec3(1.,.3*cos(time),-.2),
cd=normalize(ct-cp),
cr=normalize(cross(cd,vec3(.5*cos(.3*time),0.,1.))),
cu=cross(cr,cd),
rd=normalize(2.*cd+cr*p.x+cu*p.y);
// Trace! (+some funky lens/raster effects)
vec3 c=trace(cp,rd)*
min(1.,1.8-dot(q,q))*
(.9+.1*sin(3.*sin(gBeat)*gl_FragCoord.y));
gl_FragColor=vec4(c,1);
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with for scoping should succeed
precision mediump float;
void main() {
int k = 0;
for (int i = 0; i < 10; i++) { int i = k+i; } // ok, compound nests
gl_FragColor = vec4(float(k));
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,39 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with private function scoped struct should fail.
precision mediump float;
int fun2(struct s { int m; } g) { return g.m; }
s a;
void main() {
int e = fun2(s(3));
gl_FragColor = vec4(1.0);
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader with functional scoping should succeed
precision mediump float;
int f(int k) {
int k = k + 3;
return k;
}
void main() {
gl_FragColor = vec4(f(100));
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="vertexShader" type="text/something-not-javascript">
// vertex shader uses the long integer constant should succeed
attribute vec4 vPosition;
void main()
{
#define TEST 0x1F
int a = TEST;
gl_Position = vPosition;
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<script src="../../../resources/js-test-pre.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script src="../../resources/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader that vec4->vec3->vec4 conditional should succeed
precision mediump float;
uniform float x;
void main()
{
gl_FragColor = vec4((x > 0.0 ? vec4(1.0, 1.0, 1.0, 0.0) : vec4(0.1, 0.1, 0.1, 0.0)).xyz, 1.0);
}
</script>
<script>
GLSLConformanceTester.runTest();
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -18,10 +18,14 @@ found in the LICENSE file.
<div id="console"></div>
<script id="vertexShader" type="text/something-not-javascript">
// shader with too-deep struct nesting should fail per WebGL spec
struct nesting4 {
struct nesting5 {
vec4 vector;
};
struct nesting4 {
nesting5 field5;
};
struct nesting3 {
nesting4 field4;
};
@ -37,7 +41,7 @@ struct nesting1 {
uniform nesting1 uniform1;
void main()
{
gl_Position = uniform1.field2.field3.field4.vector;
gl_Position = uniform1.field2.field3.field4.field5.vector;
}
</script>
<script>

View File

@ -18,10 +18,14 @@ found in the LICENSE file.
<div id="console"></div>
<script id="vertexShader" type="text/something-not-javascript">
// shader with struct nesting less than maximum in WebGL spec should succeed
struct nesting3 {
struct nesting4 {
vec4 vector;
};
struct nesting3 {
nesting4 field4;
};
struct nesting2 {
nesting3 field3;
};
@ -33,7 +37,7 @@ struct nesting1 {
uniform nesting1 uniform1;
void main()
{
gl_Position = uniform1.field2.field3.vector;
gl_Position = uniform1.field2.field3.field4.vector;
}
</script>
<script>

View File

@ -41,101 +41,101 @@ found in the LICENSE file.
</script>
<script>
function init()
{
if (window.initNonKhronosFramework) {
window.initNonKhronosFramework(false);
}
if (window.initNonKhronosFramework) {
window.initNonKhronosFramework(false);
}
description("Checks gl_PointCoord and gl_PointSize");
debug("");
description("Checks gl_PointCoord and gl_PointSize");
debug("");
// NOTE: I'm not 100% confident in this test. I think it is correct.
// NOTE: I'm not 100% confident in this test. I think it is correct.
wtu = WebGLTestUtils;
gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
wtu = WebGLTestUtils;
var gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
shouldBeNonNull("gl");
shouldBe("gl.getError()", "gl.NO_ERROR");
canvas = gl.canvas;
width = canvas.width;
height = canvas.height;
shouldBeTrue("width == height");
var canvas = gl.canvas;
var width = canvas.width;
var height = canvas.height;
shouldBe("width", "height");
maxPointSize = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE)[1];
shouldBeTrue("maxPointSize >= 1");
shouldBeTrue("maxPointSize % 1 == 0");
var maxPointSize = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE)[1];
shouldBeTrue("maxPointSize >= 1");
shouldBeTrue("maxPointSize % 1 == 0");
maxPointSize = Math.min(maxPointSize, 64);
pointWidth = maxPointSize / width;
pointStep = Math.floor(maxPointSize / 4);
pointStep = Math.max(1, pointStep);
maxPointSize = Math.min(maxPointSize, 64);
var pointWidth = maxPointSize / width;
var pointStep = Math.floor(maxPointSize / 4);
var pointStep = Math.max(1, pointStep);
program = gl.program;
pointSizeLoc = gl.getUniformLocation(program, "uPointSize");
gl.uniform1f(pointSizeLoc, maxPointSize);
var program = gl.program;
var pointSizeLoc = gl.getUniformLocation(program, "uPointSize");
gl.uniform1f(pointSizeLoc, maxPointSize);
var pixelOffset = (maxPointSize % 2) ? (1 / width) : 0;
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(
[-0.5 + pixelOffset, -0.5 + pixelOffset,
0.5 + pixelOffset, -0.5 + pixelOffset,
-0.5 + pixelOffset, 0.5 + pixelOffset,
0.5 + pixelOffset, 0.5 + pixelOffset]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
var pixelOffset = (maxPointSize % 2) ? (1 / width) : 0;
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(
[-0.5 + pixelOffset, -0.5 + pixelOffset,
0.5 + pixelOffset, -0.5 + pixelOffset,
-0.5 + pixelOffset, 0.5 + pixelOffset,
0.5 + pixelOffset, 0.5 + pixelOffset]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 4);
function s2p(s) {
return (s + 1.0) * 0.5 * width;
}
gl.drawArrays(gl.POINTS, 0, 4);
shouldBe("gl.getError()", "gl.NO_ERROR");
//function print(x, y) {
// var b = new Uint8Array(4);
// gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, b);
// debug("" + x + "," + y + ": " + b[0] + "," + b[1] + "," + b[2]);
//}
//
//for (var ii = 0; ii < 100; ++ii) {
// print(ii, ii);
//}
function s2p(s) {
return (s + 1.0) * 0.5 * width;
}
for (var py = 0; py < 2; ++py) {
for (var px = 0; px < 2; ++px) {
debug("");
var pointX = -0.5 + px + pixelOffset;
var pointY = -0.5 + py + pixelOffset;
for (var yy = 0; yy < maxPointSize; yy += pointStep) {
for (var xx = 0; xx < maxPointSize; xx += pointStep) {
// formula for s and t from OpenGL ES 2.0 spec section 3.3
var xw = s2p(pointX);
var yw = s2p(pointY);
//debug("xw: " + xw + " yw: " + yw);
var u = xx / maxPointSize * 2 - 1;
var v = yy / maxPointSize * 2 - 1;
var xf = Math.floor(s2p(pointX + u * pointWidth));
var yf = Math.floor(s2p(pointY + v * pointWidth));
//debug("xf: " + xf + " yf: " + yf);
var s = 0.5 + (xf + 0.5 - xw) / maxPointSize;
var t = 0.5 + (yf + 0.5 - yw) / maxPointSize;
//debug("s: " + s + " t: " + t);
var color = [Math.floor(s * 255), Math.floor((1 - t) * 255), 0];
var msg = "pixel " + xf + "," + yf + " should be " + color;
wtu.checkCanvasRect(gl, xf, yf, 1, 1, color, msg, 4);
}
//function print(x, y) {
// var b = new Uint8Array(4);
// gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, b);
// debug("" + x + "," + y + ": " + b[0] + "," + b[1] + "," + b[2]);
//}
//
//for (var ii = 0; ii < 100; ++ii) {
// print(ii, ii);
//}
for (var py = 0; py < 2; ++py) {
for (var px = 0; px < 2; ++px) {
debug("");
var pointX = -0.5 + px + pixelOffset;
var pointY = -0.5 + py + pixelOffset;
for (var yy = 0; yy < maxPointSize; yy += pointStep) {
for (var xx = 0; xx < maxPointSize; xx += pointStep) {
// formula for s and t from OpenGL ES 2.0 spec section 3.3
var xw = s2p(pointX);
var yw = s2p(pointY);
//debug("xw: " + xw + " yw: " + yw);
var u = xx / maxPointSize * 2 - 1;
var v = yy / maxPointSize * 2 - 1;
var xf = Math.floor(s2p(pointX + u * pointWidth));
var yf = Math.floor(s2p(pointY + v * pointWidth));
//debug("xf: " + xf + " yf: " + yf);
var s = 0.5 + (xf + 0.5 - xw) / maxPointSize;
var t = 0.5 + (yf + 0.5 - yw) / maxPointSize;
//debug("s: " + s + " t: " + t);
var color = [Math.floor(s * 255), Math.floor((1 - t) * 255), 0];
var msg = "pixel " + xf + "," + yf + " should be " + color;
wtu.checkCanvasRect(gl, xf, yf, 1, 1, color, msg, 4);
}
}
}
}
init();
successfullyParsed = true;
</script>
<script src="../../../resources/js-test-post.js"></script>
<script src="../../../resources/js-test-post.js"></script>
</body>
</html>

View File

@ -1,9 +1,11 @@
bad-arguments-test.html
--min-version 1.0.2 delayed-drawing.html
error-reporting.html
instanceof-test.html
invalid-passed-params.html
is-object.html
null-object-behaviour.html
functions-returning-strings.html
object-deletion-behaviour.html
shader-precision-format.html
type-conversion-test.html

View File

@ -0,0 +1,63 @@
<!--
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 Delayed Drawing test.</title>
<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 src="../resources/webgl-test-utils.js"> </script>
</head>
<body>
<canvas id="example" width="4" height="4" style="width: 40px; height: 30px;"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
description(document.title);
var wtu = WebGLTestUtils;
var canvas = document.getElementById("example");
var gl = wtu.create3DContext(canvas);
var program = wtu.setupTexturedQuad(gl);
glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
var tex = gl.createTexture();
wtu.fillTexture(gl, tex, 5, 3, [0, 192, 128, 255]);
var loc = gl.getUniformLocation(program, "tex");
gl.uniform1i(loc, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
drawAndCheck();
setTimeout(step2, 1000);
function step2() {
drawAndCheck();
finishTest();
}
function drawAndCheck() {
glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors before drawing.");
wtu.drawQuad(gl);
glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from drawing.");
wtu.checkCanvas(
gl, [0, 192, 128, 255],
"draw should be 0, 192, 128, 255");
}
successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,92 @@
<!--
Copyright (c) 2012 Mozilla Foundation. 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 Conformance Tests</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<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>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="2" height="2"> </canvas>
<script>
description("Test that functions returning strings really do return strings (and not e.g. null)");
debug("");
var validVertexShaderString =
"attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }";
var validFragmentShaderString =
"precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }";
function shouldReturnString(_a)
{
var exception;
var _av;
try {
_av = eval(_a);
} catch (e) {
exception = e;
}
if (exception)
testFailed(_a + ' should return a string. Threw exception ' + exception);
else if (typeof _av == "string")
testPassed(_a + ' returns a string: "' + _av + '"');
else
testFailed(_a + ' should return a string. Returns: "' + _av + '"');
}
var gl = create3DContext(document.getElementById("canvas"));
if (!gl) {
testFailed("context does not exist");
} else {
var vs = gl.createShader(gl.VERTEX_SHADER);
shouldReturnString("gl.getShaderSource(vs)");
shouldReturnString("gl.getShaderInfoLog(vs)");
gl.shaderSource(vs, validVertexShaderString);
gl.compileShader(vs);
shouldReturnString("gl.getShaderSource(vs)");
shouldReturnString("gl.getShaderInfoLog(vs)");
var fs = gl.createShader(gl.FRAGMENT_SHADER);
shouldReturnString("gl.getShaderSource(fs)");
shouldReturnString("gl.getShaderInfoLog(fs)");
gl.shaderSource(fs, validFragmentShaderString);
gl.compileShader(fs);
shouldReturnString("gl.getShaderSource(fs)");
shouldReturnString("gl.getShaderInfoLog(fs)");
var prog = gl.createProgram();
shouldReturnString("gl.getProgramInfoLog(prog)");
gl.attachShader(prog, vs);
gl.attachShader(prog, fs);
gl.linkProgram(prog);
shouldReturnString("gl.getProgramInfoLog(prog)");
var exts = gl.getSupportedExtensions();
for (i in exts) {
shouldReturnString("gl.getSupportedExtensions()[" + i + "]");
}
shouldReturnString("gl.getParameter(gl.VENDOR)");
shouldReturnString("gl.getParameter(gl.RENDERER)");
shouldReturnString("gl.getParameter(gl.VERSION)");
shouldReturnString("gl.getParameter(gl.SHADING_LANGUAGE_VERSION)");
}
debug("");
successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>

View File

@ -137,7 +137,10 @@ var program = context.createProgram();
context.attachShader(program, vShader);
context.attachShader(program, fShader);
context.linkProgram(program);
shouldBeTrue("context.getProgramParameter(program, context.LINK_STATUS)");
var linkStatus = context.getProgramParameter(program, context.LINK_STATUS);
shouldBeTrue("linkStatus");
if (!linkStatus)
debug(context.getProgramInfoLog(program));
shouldBe("context.getError()", "context.NO_ERROR");
context.bindAttribLocation(program, 1, validAttribName);
shouldBe("context.getError()", "context.NO_ERROR");

View File

@ -42,7 +42,7 @@ debug("");
debug("Canvas.getContext");
var gl = create3DContext(document.getElementById("canvas"));
shouldBeNonNull(gl);
shouldBeNonNull("gl");
function fail(x,y, buf, shouldBe)
{

View File

@ -81,8 +81,9 @@ function go() {
gl.shaderSource(vsBad, "WILL NOT COMPILE;");
gl.compileShader(vsBad);
assertMsg(gl.getShaderParameter(vsBad, gl.COMPILE_STATUS) == false,
"bad vertex shader should fail to compile");
// GLSL 1.0.17 section 10.27. compile shader does not have to return failure.
//assertMsg(gl.getShaderParameter(vsBad, gl.COMPILE_STATUS) == false,
// "bad vertex shader should fail to compile");
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }");
@ -102,8 +103,9 @@ function go() {
gl.shaderSource(fsBad, "WILL NOT COMPILE;");
gl.compileShader(fsBad);
assertMsg(gl.getShaderParameter(fsBad, gl.COMPILE_STATUS) == false,
"bad fragment shader should fail to compile");
// GLSL 1.0.17 section 10.27. compile shader does not have to return failure.
//assertMsg(gl.getShaderParameter(fsBad, gl.COMPILE_STATUS) == false,
// "bad fragment shader should fail to compile");
glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors at this point");
@ -196,8 +198,13 @@ function go() {
if (gl.getError() != gl.NO_ERROR)
assertMsg(false, "unexpected error in linkProgram()");
assertMsg(gl.getProgramParameter(prog, gl.LINK_STATUS) == expected_status, errmsg);
var infolog = gl.getProgramInfoLog(prog);
if (gl.getError() != gl.NO_ERROR)
assertMsg(false, "unexpected error in getProgramInfoLog()");
if (typeof(infolog) != "string")
assertMsg(false, "getProgramInfoLog() did not return a string");
if (expected_status == true && gl.getProgramParameter(prog, gl.LINK_STATUS) == false)
debug(gl.getProgramInfoLog(prog));
debug(infolog);
if (gl.getError() != gl.NO_ERROR)
assertMsg(false, "unexpected error in getProgramParameter()");
gl.useProgram(prog);
@ -252,6 +259,10 @@ function go() {
assertMsg(gl.getProgramParameter(progGood2, gl.LINK_STATUS) == false,
"linking should fail with in-use formerly good program, with new bad shader attached");
// Invalid link leaves previous valid program intact.
gl.drawArrays(gl.TRIANGLES, 0, 3);
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error");
gl.useProgram(progGood1);
gl.drawArrays(gl.TRIANGLES, 0, 4);
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid when last used program shouldn't generate a GL error");

View File

@ -191,7 +191,7 @@ function runTestIteration(format, type, packAlignment, width, height)
for (var i = numComponents; i < 4; ++i)
pixel[i] = 0;
expectedColor = packColor(format, type, 255, 102, 0, 255);
shouldBeNonNull(expectedColor);
shouldBeNonNull("expectedColor");
shouldBe("pixel", "expectedColor");
}

View File

@ -71,6 +71,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (j < w * 4 || j > w * (w - 1) * 4 || j % (w * 4) == 0 || j % (w * 4) == (w - 1) * 4) {
correct = green;
}
// ignore corner pixels
if ((j == 0) || (j == 4*(w-1)) || (j == 4*w*(w-1)) || (j== 4*(w*w - 1))) {
continue;
}
if (!checkPixel(buf, j, correct)) {
isCorrect = false;
break;

View File

@ -11,37 +11,40 @@ found in the LICENSE file.
<script src="../../resources/js-test-pre.js"></script>
<script src="../resources/webgl-test.js"></script>
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 pos;
attribute vec4 colorIn;
uniform float pointSize;
varying vec4 color;
attribute vec3 pos;
attribute vec4 colorIn;
uniform float pointSize;
varying vec4 color;
void main()
{
gl_PointSize = pointSize;
color = colorIn;
gl_Position = vec4(pos.xyz, 3.0);
}
void main()
{
gl_PointSize = pointSize;
color = colorIn;
gl_Position = vec4(pos, 1.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 color;
precision mediump float;
varying vec4 color;
void main()
{
gl_FragColor = color;
}
</script>
<script>
function runTest()
{
var gl = initWebGL('testbed', 'vshader', 'fshader', ['pos', 'colorIn'], [0, 0, 0, 1], 1, { antialias: false });
if (!gl) {
testFailed('initWebGL(..) failed');
return false;
void main()
{
gl_FragColor = color;
}
</script>
</head>
<body>
<canvas id="testbed" width="2px" height="2px"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
description('Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled in WebGL');
var gl = initWebGL('testbed', 'vshader', 'fshader', ['pos', 'colorIn'], [0, 0, 0, 1], 1, { antialias: false });
shouldBeNonNull("gl");
shouldBe('gl.getError()', 'gl.NO_ERROR');
gl.disable(gl.BLEND);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
@ -68,22 +71,27 @@ function runTest()
var locPointSize = gl.getUniformLocation(gl.program, 'pointSize');
shouldBe('gl.getError()', 'gl.NO_ERROR');
debug('Draw a point of size 1 and verify it does not touch any other pixels.');
gl.uniform1f(locPointSize, 1.0);
gl.drawArrays(gl.POINTS, 0, vertices.length / 3);
var buf = new Uint8Array(2 * 2 * 4);
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, buf);
shouldBe('gl.getError()', 'gl.NO_ERROR');
var index = 0;
var correctColor;
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < 2; ++x) {
var correctColor = [0, 0, 0];
correctColor = [0, 0, 0];
if (x == 1 && y == 1)
correctColor[0] = 255;
if (buf[index] != correctColor[0] || buf[index + 1] != correctColor[1] || buf[index + 2] != correctColor[2]) {
testFailed('Drawing a point of size 1 touched pixels that should not be touched');
return false;
}
shouldBe('buf[index]', '255');
else
shouldBe('buf[index]', '0');
shouldBe('buf[index + 1]', '0');
shouldBe('buf[index + 2]', '0');
index += 4;
}
}
@ -92,39 +100,23 @@ function runTest()
debug('Draw a point of size 2 and verify it fills the appropriate region.');
var pointSizeRange = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
if (pointSizeRange < 2.0)
return true;
gl.uniform1f(locPointSize, 2.0);
gl.drawArrays(gl.POINTS, 0, vertices.length / 3);
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, buf);
index = 0;
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < 2; ++x) {
var correctColor = [255, 0, 0];
if (buf[index] != correctColor[0] || buf[index + 1] != correctColor[1] || buf[index + 2] != correctColor[2]) {
testFailed('Drawing a point of size 2 failed to fill the appropriate region');
return false;
if (pointSizeRange[1] >= 2.0) {
gl.uniform1f(locPointSize, 2.0);
gl.drawArrays(gl.POINTS, 0, vertices.length / 3);
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, buf);
shouldBe('gl.getError()', 'gl.NO_ERROR');
index = 0;
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < 2; ++x) {
shouldBe('buf[index]', '255');
shouldBe('buf[index + 1]', '0');
shouldBe('buf[index + 2]', '0');
index += 4;
}
index += 4;
}
}
return true;
}
</script>
</head>
<body>
<canvas id="testbed" width="2px" height="2px"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
description('Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled in WebGL');
if (runTest())
testPassed("");
successfullyParsed = true;
successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>

View File

@ -71,10 +71,11 @@ function runOneTest(gl, info) {
return;
}
}
if ((vShader != null) != info.vShaderSuccess) {
// As per GLSL 1.0.17 10.27 we can only check for success on
// compileShader, not failure.
if (info.vShaderSuccess && !vShader) {
testFailed("[unexpected vertex shader compile status] (expected: " +
info.vShaderSuccess + ") " + passMsg);
return;
info.vShaderSuccess + ") " + passMsg);
}
// Save the shaders so we test shared shader.
if (vShader) {
@ -96,7 +97,9 @@ function runOneTest(gl, info) {
}
}
//debug(fShader == null ? "fail" : "succeed");
if ((fShader != null) != info.fShaderSuccess) {
// As per GLSL 1.0.17 10.27 we can only check for success on
// compileShader, not failure.
if (info.fShaderSuccess && !fShader) {
testFailed("[unexpected fragment shader compile status] (expected: " +
info.fShaderSuccess + ") " + passMsg);
return;

View File

@ -587,6 +587,7 @@ var glErrorShouldBe = function(gl, glError, opt_msg) {
* @param {function(string): void) opt_errorCallback callback for errors.
*/
var linkProgram = function(gl, program, opt_errorCallback) {
errFn = opt_errorCallback || testFailed;
// Link the program
gl.linkProgram(program);
@ -596,7 +597,7 @@ var linkProgram = function(gl, program, opt_errorCallback) {
// something went wrong with the link
var error = gl.getProgramInfoLog (program);
testFailed("Error in program linking:" + error);
errFn("Error in program linking:" + error);
gl.deleteProgram(program);
}
@ -931,7 +932,7 @@ var loadShaderFromScript = function(
var shaderType;
var shaderScript = document.getElementById(scriptId);
if (!shaderScript) {
throw("*** Error: unknown script element" + scriptId);
throw("*** Error: unknown script element " + scriptId);
}
shaderSource = shaderScript.text;
@ -1032,6 +1033,41 @@ var loadProgram = function(
return program;
};
/**
* Loads shaders from source, creates a program, attaches the shaders and
* links but expects error.
*
* GLSL 1.0.17 10.27 effectively says that compileShader can
* always succeed as long as linkProgram fails so we can't
* rely on compileShader failing. This function expects
* one of the shader to fail OR linking to fail.
*
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {string} vertexShaderScriptId The vertex shader.
* @param {string} fragmentShaderScriptId The fragment shader.
* @return {WebGLProgram} The created program.
*/
var loadProgramFromScriptExpectError = function(
gl, vertexShaderScriptId, fragmentShaderScriptId) {
var vertexShader = loadShaderFromScript(gl, vertexShaderScriptId);
if (!vertexShader) {
return null;
}
var fragmentShader = loadShaderFromScript(gl, fragmentShaderScriptId);
if (!fragmentShader) {
return null;
}
var linkSuccess = true;
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
linkSuccess = true;
linkProgram(gl, program, function() {
linkSuccess = false;
});
return linkSuccess ? program : null;
};
var basePath;
var getBasePath = function() {
if (!basePath) {
@ -1144,6 +1180,7 @@ return {
loadProgram: loadProgram,
loadProgramFromFile: loadProgramFromFile,
loadProgramFromScript: loadProgramFromScript,
loadProgramFromScriptExpectError: loadProgramFromScriptExpectError,
loadShader: loadShader,
loadShaderFromFile: loadShaderFromFile,
loadShaderFromScript: loadShaderFromScript,

View File

@ -1,3 +1,4 @@
compressed-tex-image.html
copy-tex-image-and-sub-image-2d.html
gl-pixelstorei.html
gl-teximage.html

View File

@ -0,0 +1,61 @@
<!--
Copyright (c) 2012 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 CompressedTexImage and CompressedTexSubImage Tests</title>
<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 src="../resources/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description("This test ensures WebGL implementations correctly implement compressedTexImage2D and compressedTexSubImage2D.");
debug("");
var wtu = WebGLTestUtils;
var canvas = document.createElement("canvas");
var gl = wtu.create3DContext(canvas);
const COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
const COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
const COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
const ETC1_RGB8_OES = 0x8D64;
const COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
const COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
var formats = null;
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, new Uint8Array(8))");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 0, new Uint8Array(8))");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_S3TC_DXT5_EXT, 4, 4, 0, new Uint8Array(16))");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ETC1_RGB8_OES, 4, 4, 0, new Uint8Array(8))");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
shouldGenerateGLError(gl, gl.NO_ERROR, "formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)");
shouldBeNonNull("formats");
shouldBe("formats.length", "0");
}
successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>

View File

@ -149,6 +149,7 @@ function testSize(size) {
var err = gl.getError();
if (err == gl.OUT_OF_MEMORY) {
debug("out of memory");
return false;
}
if (err != gl.NO_ERROR) {

View File

@ -96,7 +96,7 @@ function runTest() {
return false;
}
}
return true;
return true;
}
if (doTest()) {
@ -120,10 +120,11 @@ function checkTexture(width, height, cubeMap) {
fillLevel(0, width, height, color.rgba, cubeMap);
var err = gl.getError();
if (err == gl.OUT_OF_MEMORY) {
return false;
debug("out of memory");
return false;
}
if (err != gl.NO_ERROR) {
testFailed("unexpected gl error: " + wtu.glEnumToString(gl, err));
testFailed("unexpected gl error: " + wtu.glEnumToString(gl, err));
}
wtu.drawQuad(gl);
wtu.checkCanvas(gl, color.rgba,
@ -134,6 +135,7 @@ function checkTexture(width, height, cubeMap) {
gl.generateMipmap(target);
var err = gl.getError();
if (err == gl.OUT_OF_MEMORY) {
debug("out of memory");
return false;
}
if (err != gl.NO_ERROR) {
@ -182,7 +184,7 @@ function fillLevel(level, width, height, color, opt_cubemap) {
[gl.TEXTURE_2D];
for (var ii = 0; ii < targets.length; ++ii) {
// debug(wtu.glEnumToString(gl, targets[ii]));
// debug(wtu.glEnumToString(gl, targets[ii]));
gl.texImage2D(
targets[ii], level, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
pixels);

View File

@ -90,6 +90,58 @@ function printSummary() {
}
}
var byteLength;
var subBuffer;
function testSlice() {
function test(subBuf, starts, size) {
byteLength = size;
subBuffer = eval(subBuf);
var subArray = new Int8Array(subBuffer);
assertEq(subBuf, subBuffer.byteLength, byteLength);
for (var i = 0; i < size; ++i)
assertEq('Element ' + i, starts + i, subArray[i]);
}
try {
running('testSlice');
var buffer = new ArrayBuffer(32);
var array = new Int8Array(buffer);
for (var i = 0; i < 32; ++i)
array[i] = i;
test("buffer.slice(0)", 0, 32);
test("buffer.slice(16)", 16, 16);
test("buffer.slice(24)", 24, 8);
test("buffer.slice(32)", 32, 0);
test("buffer.slice(40)", 32, 0);
test("buffer.slice(80)", 32, 0);
test("buffer.slice(-8)", 24, 8);
test("buffer.slice(-16)", 16, 16);
test("buffer.slice(-24)", 8, 24);
test("buffer.slice(-32)", 0, 32);
test("buffer.slice(-40)", 0, 32);
test("buffer.slice(-80)", 0, 32);
test("buffer.slice(0, 32)", 0, 32);
test("buffer.slice(0, 16)", 0, 16);
test("buffer.slice(8, 24)", 8, 16);
test("buffer.slice(16, 32)", 16, 16);
test("buffer.slice(24, 16)", 24, 0);
test("buffer.slice(16, -8)", 16, 8);
test("buffer.slice(-20, 30)", 12, 18);
test("buffer.slice(-8, -20)", 24, 0);
test("buffer.slice(-20, -8)", 12, 12);
test("buffer.slice(-40, 16)", 0, 16);
test("buffer.slice(-40, 40)", 0, 32);
pass();
} catch (e) {
fail(e);
}
}
//
// Tests for unsigned array variants
//
@ -202,7 +254,11 @@ function testIntegralArrayTruncationBehavior(type, name, unsigned) {
if (unsigned) {
sourceData = [0.6, 10.6];
expectedResults = [0, 10];
if (type === Uint8ClampedArray) {
expectedResults = [1, 11];
} else {
expectedResults = [0, 10];
}
} else {
sourceData = [0.6, 10.6, -0.6, -10.6];
expectedResults = [0, 10, 0, -10];
@ -249,6 +305,14 @@ function testIntegralArrayTruncationBehavior(type, name, unsigned) {
}
}
break;
case Uint8ClampedArray:
for (var ii = 0; ii < sourceData.length; ++ii) {
for (var jj = 0; jj < numIterations; ++jj) {
array[jj] = sourceData[ii];
assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]);
}
}
break;
case Uint16Array:
for (var ii = 0; ii < sourceData.length; ++ii) {
for (var jj = 0; jj < numIterations; ++jj) {
@ -519,14 +583,18 @@ function testConstructionWithOutOfRangeValues(type, name) {
}, "Construction of " + name + " with out-of-range offset");
}
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");
}
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");
}
shouldThrowIndexSizeErr(function() {
var buffer = new ArrayBuffer(4);
@ -644,20 +712,95 @@ function testSubarrayWithDefaultValues(type, name, sz) {
}
}
function testSettingFromArrayWithOutOfRangeOffset(type, name) {
var webglArray = new type(32);
var array = [];
for (var i = 0; i < 16; i++) {
array.push(i);
}
function setWithInvalidOffset(type, name, length,
sourceType, sourceName, sourceLength,
offset, offsetDescription) {
var webglArray = new type(length);
var sourceArray = new sourceType(sourceLength);
for (var i = 0; i < sourceLength; i++)
sourceArray[i] = 42 + i;
try {
webglArray.set(array, 0x7FFFFFF8);
testFailed("Setting " + name + " from array with out-of-range offset was not caught");
webglArray.set(sourceArray, offset);
testFailed("Setting " + name + " from " + sourceName + " with " +
offsetDescription + " offset was not caught");
} catch (e) {
testPassed("Setting " + name + " from array with out-of-range offset was caught");
testPassed("Setting " + name + " from " + sourceName + " with " +
offsetDescription + " offset was caught");
}
}
function setWithValidOffset(type, name, length,
sourceType, sourceName, sourceLength,
offset, offsetDescription) {
running("Setting " + name + " from " + sourceName + " with " +
offsetDescription + " offset");
var webglArray = new type(length);
var sourceArray = new sourceType(sourceLength);
for (var i = 0; i < sourceLength; i++)
sourceArray[i] = 42 + i;
try {
webglArray.set(sourceArray, offset);
offset = Math.floor(offset);
for (var i = 0; i < sourceLength; i++) {
assertEq("Element " + i + offset, sourceArray[i], webglArray[i + offset]);
}
pass();
} catch (e) {
fail(e);
}
}
function testSettingFromArrayWithOutOfRangeOffset(type, name) {
setWithInvalidOffset(type, name, 32, Array, "array", 16,
0x7FFFFFF8, "out-of-range");
}
function testSettingFromTypedArrayWithOutOfRangeOffset(type, name) {
setWithInvalidOffset(type, name, 32, type, name, 16,
0x7FFFFFF8, "out-of-range");
}
function testSettingFromArrayWithNegativeOffset(type, name) {
setWithInvalidOffset(type, name, 32, Array, "array", 16,
-1, "negative");
}
function testSettingFromTypedArrayWithNegativeOffset(type, name) {
setWithInvalidOffset(type, name, 32, type, name, 16,
-1, "negative");
}
function testSettingFromArrayWithMinusZeroOffset(type, name) {
setWithValidOffset(type, name, 32, Array, "array", 16,
-0, "-0");
}
function testSettingFromTypedArrayWithMinusZeroOffset(type, name) {
setWithValidOffset(type, name, 32, type, name, 16,
-0, "-0");
}
function testSettingFromArrayWithBoundaryOffset(type, name) {
setWithValidOffset(type, name, 32, Array, "array", 16,
16, "boundary");
}
function testSettingFromTypedArrayWithBoundaryOffset(type, name) {
setWithValidOffset(type, name, 32, type, name, 16,
16, "boundary");
}
function testSettingFromArrayWithNonIntegerOffset(type, name) {
setWithValidOffset(type, name, 32, Array, "array", 16,
16.999, "non-integer");
}
function testSettingFromTypedArrayWithNonIntegerOffset(type, name) {
setWithValidOffset(type, name, 32, type, name, 16,
16.999, "non-integer");
}
function testSettingFromFakeArrayWithOutOfRangeLength(type, name) {
var webglArray = new type(32);
var array = {};
@ -670,19 +813,6 @@ function testSettingFromFakeArrayWithOutOfRangeLength(type, name) {
}
}
function testSettingFromTypedArrayWithOutOfRangeOffset(type, name) {
var webglArray = new type(32);
var srcArray = new type(16);
for (var i = 0; i < 16; i++) {
srcArray[i] = i;
}
try {
webglArray.set(srcArray, 0x7FFFFFF8);
testFailed("Setting " + name + " from " + name + " with out-of-range offset was not caught");
} catch (e) {
testPassed("Setting " + name + " from " + name + " with out-of-range offset was caught");
}
}
function negativeTestGetAndSetMethods(type, name) {
array = new type([2, 3]);
@ -751,6 +881,12 @@ function testNaNConversion(type, name) {
results[i] = array[i];
}
break;
case Uint8ClampedArray:
for (var i = 0; i < array.length; ++i) {
array[i] = NaN;
results[i] = array[i];
}
break;
case Uint16Array:
for (var i = 0; i < array.length; ++i) {
array[i] = NaN;
@ -792,6 +928,8 @@ function testNaNConversion(type, name) {
function runTests() {
allPassed = true;
testSlice();
// The "name" attribute is a concession to browsers which don't
// implement the "name" property on function objects
var testCases =
@ -837,6 +975,13 @@ function runTests() {
testValues: [ 0, 255, -1, 256 ],
expectedValues: [ 0, 255, 255, 0 ]
},
{name: "Uint8ClampedArray",
unsigned: true,
integral: true,
elementSizeInBytes: 1,
testValues: [ 0, 255, -1, 256 ],
expectedValues: [ 0, 255, 0, 255 ]
},
{name: "Uint16Array",
unsigned: true,
integral: true,
@ -891,7 +1036,7 @@ function runTests() {
testCase.expectedValues);
testConstructionWithNullBuffer(type, name);
testConstructionWithOutOfRangeValues(type, name);
testConstructionWithNegativeOutOfRangeValues(type, name, testCase.elementSizeInBytes);
testConstructionWithNegativeOutOfRangeValues(type, name);
testConstructionWithUnalignedOffset(type, name, testCase.elementSizeInBytes);
testConstructionWithUnalignedLength(type, name, testCase.elementSizeInBytes);
testConstructionOfHugeArray(type, name, testCase.elementSizeInBytes);
@ -900,8 +1045,16 @@ function runTests() {
testSubarrayWithOutOfRangeValues(type, name, testCase.elementSizeInBytes);
testSubarrayWithDefaultValues(type, name, testCase.elementSizeInBytes);
testSettingFromArrayWithOutOfRangeOffset(type, name);
testSettingFromFakeArrayWithOutOfRangeLength(type, name);
testSettingFromTypedArrayWithOutOfRangeOffset(type, name);
testSettingFromArrayWithNegativeOffset(type, name);
testSettingFromTypedArrayWithNegativeOffset(type, name);
testSettingFromArrayWithMinusZeroOffset(type, name);
testSettingFromTypedArrayWithMinusZeroOffset(type, name);
testSettingFromArrayWithBoundaryOffset(type, name);
testSettingFromTypedArrayWithBoundaryOffset(type, name);
testSettingFromArrayWithNonIntegerOffset(type, name);
testSettingFromTypedArrayWithNonIntegerOffset(type, name);
testSettingFromFakeArrayWithOutOfRangeLength(type, name);
negativeTestGetAndSetMethods(type, name);
testNaNConversion(type, name);
}

View File

@ -1,5 +1,5 @@
# HG changeset patch
# Parent 07fbbfde4173da7d8e513bb2d52ae07e333dbf43
# Parent 30d84739fa6136571e995045960c3fd90b44382c
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

View File

@ -10,5 +10,4 @@ conformance/more/conformance/quickCheckAPI-S_V.html
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/glsl/misc/struct-nesting-exceeds-maximum.html
conformance/renderbuffers/framebuffer-object-attachment.html

View File

@ -8,4 +8,4 @@ conformance/more/functions/uniformfBadArgs.html
conformance/more/functions/uniformiBadArgs.html
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/glsl/misc/struct-nesting-exceeds-maximum.html
conformance/programs/program-test.html

View File

@ -8,5 +8,4 @@ conformance/more/conformance/quickCheckAPI-S_V.html
conformance/more/functions/uniformfArrayLen1.html
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/glsl/misc/struct-nesting-exceeds-maximum.html
conformance/glsl/misc/uniform-location-length-limits.html

View File

@ -0,0 +1,22 @@
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
@@ -362,18 +362,16 @@ TestHarness.prototype.addFiles_ = functi
}
log("total files: " + files.length);
for (var ii = 0; ii < files.length; ++ii) {
log("" + ii + ": " + files[ii]);
this.files.push(new TestFile(files[ii]));
this.reportFunc(TestHarness.reportType.ADD_PAGE, files[ii], undefined);
}
this.reportFunc(TestHarness.reportType.READY, undefined, undefined);
- this.nextFileIndex = files.length;
- this.lastFileIndex = files.length;
}
TestHarness.prototype.runTests = function(opt_start, opt_count) {
var count = opt_count || this.files.length;
this.nextFileIndex = opt_start || 0;
this.lastFileIndex = this.nextFileIndex + count;
this.startNextFile();
};

View File

@ -1,5 +1,5 @@
# HG changeset patch
# Parent 1910ae60536dce7272cb0478089bf40806666de8
# Parent 0122002fbffad16de0690a21aa87d0999d0cdcb9
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

View File

@ -1,9 +1,9 @@
# HG changeset patch
# Parent a41d853e5110aca4f2c77c63db502f670d0e50a1
# Parent efec656cc42addae5aa96c6691031d54d46436fe
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
@@ -107,17 +107,18 @@ if (!gl) {
@@ -115,17 +115,18 @@ if (!gl) {
} else {
testPassed("Successfully enabled OES_standard_derivatives extension");

View File

@ -95,9 +95,11 @@ var log = function(msg) {
/**
* Loads text from an external file. This function is synchronous.
* @param {string} url The url of the external file.
* @return {string} the loaded text if the request is synchronous.
* @param {!function(bool, string): void} callback that is sent a bool for
* success and the string.
*/
var loadTextFileSynchronous = function(url) {
var loadTextFileAsynchronous = function(url, callback) {
log ("loading: " + url);
var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
var request;
if (window.XMLHttpRequest) {
@ -108,50 +110,242 @@ var loadTextFileSynchronous = function(url) {
} else {
throw 'XMLHttpRequest is disabled';
}
request.open('GET', url, false);
request.send(null);
if (request.readyState != 4) {
throw error;
try {
request.open('GET', url, true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var text = '';
// HTTP reports success with a 200 status. The file protocol reports
// success with zero. HTTP does not use zero as a status code (they
// start at 100).
// https://developer.mozilla.org/En/Using_XMLHttpRequest
var success = request.status == 200 || request.status == 0;
if (success) {
text = request.responseText;
}
log("loaded: " + url);
callback(success, text);
}
};
request.send(null);
} catch (e) {
log("failed to load: " + url);
callback(false, '');
}
return request.responseText;
};
var getFileList = function(url) {
var files = [];
if (url.substr(url.length - 4) == '.txt') {
var lines = loadTextFileSynchronous(url).split('\n');
var prefix = '';
var lastSlash = url.lastIndexOf('/');
if (lastSlash >= 0) {
prefix = url.substr(0, lastSlash + 1);
/**
* Compare version strings.
*/
var greaterThanOrEqualToVersion = function(have, want) {
have = have.split(" ")[0].split(".");
want = want.split(" ")[0].split(".");
//have 1.2.3 want 1.1
//have 1.1.1 want 1.1
//have 1.0.9 want 1.1
//have 1.1 want 1.1.1
for (var ii = 0; ii < want.length; ++ii) {
var wantNum = parseInt(want[ii]);
var haveNum = have[ii] ? parseInt(have[ii]) : 0
if (haveNum < wantNum) {
return false;
}
for (var ii = 0; ii < lines.length; ++ii) {
var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
if (str.length > 4 &&
str[0] != '#' &&
str[0] != ";" &&
str.substr(0, 2) != "//") {
new_url = prefix + str;
files = files.concat(getFileList(new_url));
}
return true;
};
/**
* Reads a file, recursively adding files referenced inside.
*
* Each line of URL is parsed, comments starting with '#' or ';'
* or '//' are stripped.
*
* arguments beginning with -- are extracted
*
* lines that end in .txt are recursively scanned for more files
* other lines are added to the list of files.
*
* @param {string} url The url of the file to read.
* @param {void function(boolean, !Array.<string>)} callback.
* Callback that is called with true for success and an
* array of filenames.
* @param {Object} options. Optional options
*
* Options:
* version: {string} The version of the conformance test.
* Tests with the argument --min-version <version> will
* be ignored version is less then <version>
*
*/
var getFileList = function(url, callback, options) {
var files = [];
var copyObject = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
var toCamelCase = function(str) {
return str.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase() });
};
var globalOptions = copyObject(options);
globalOptions.defaultVersion = "1.0";
var getFileListImpl = function(prefix, line, hierarchicalOptions, callback) {
var files = [];
var args = line.split(/\s+/);
var nonOptions = [];
var useTest = true;
var testOptions = {};
for (var jj = 0; jj < args.length; ++jj) {
var arg = args[jj];
if (arg[0] == '-') {
if (arg[1] != '-') {
throw ("bad option at in " + url + ":" + (ii + 1) + ": " + str);
}
var option = arg.substring(2);
switch (option) {
case 'min-version':
++jj;
testOptions[toCamelCase(option)] = args[jj];
break;
default:
throw ("bad unknown option '" + option + "' at in " + url + ":" + (ii + 1) + ": " + str);
}
} else {
nonOptions.push(arg);
}
}
} else {
files.push(url);
}
return files;
}
var url = prefix + nonOptions.join(" ");
if (url.substr(url.length - 4) != '.txt') {
var minVersion = testOptions.minVersion;
if (!minVersion) {
minVersion = hierarchicalOptions.defaultVersion;
}
if (globalOptions.minVersion) {
useTest = greaterThanOrEqualToVersion(minVersion, globalOptions.minVersion);
} else {
useTest = greaterThanOrEqualToVersion(globalOptions.version, minVersion);
}
}
if (!useTest) {
callback(true, []);
return;
}
if (url.substr(url.length - 4) == '.txt') {
// If a version was explicity specified pass it down.
if (testOptions.minVersion) {
hierarchicalOptions.defaultVersion = testOptions.minVersion;
}
loadTextFileAsynchronous(url, function() {
return function(success, text) {
if (!success) {
callback(false, '');
return;
}
var lines = text.split('\n');
var prefix = '';
var lastSlash = url.lastIndexOf('/');
if (lastSlash >= 0) {
prefix = url.substr(0, lastSlash + 1);
}
var fail = false;
var count = 1;
var index = 0;
for (var ii = 0; ii < lines.length; ++ii) {
var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
if (str.length > 4 &&
str[0] != '#' &&
str[0] != ";" &&
str.substr(0, 2) != "//") {
++count;
getFileListImpl(prefix, str, copyObject(hierarchicalOptions), function(index) {
return function(success, new_files) {
log("got files: " + new_files.length);
if (success) {
files[index] = new_files;
}
finish(success);
};
}(index++));
}
}
finish(true);
function finish(success) {
if (!success) {
fail = true;
}
--count;
log("count: " + count);
if (!count) {
callback(!fail, files);
}
}
}
}());
} else {
files.push(url);
callback(true, files);
}
};
getFileListImpl('', url, globalOptions, function(success, files) {
// flatten
var flat = [];
flatten(files);
function flatten(files) {
for (var ii = 0; ii < files.length; ++ii) {
var value = files[ii];
if (typeof(value) == "string") {
flat.push(value);
} else {
flatten(value);
}
}
}
callback(success, flat);
});
};
var TestFile = function(url) {
this.url = url;
};
var TestHarness = function(iframe, filelistUrl, reportFunc) {
var TestHarness = function(iframe, filelistUrl, reportFunc, options) {
this.window = window;
this.iframe = iframe;
this.reportFunc = reportFunc;
try {
var files = getFileList(filelistUrl);
} catch (e) {
this.timeoutDelay = 20000;
this.files = [];
var that = this;
getFileList(filelistUrl, function() {
return function(success, files) {
that.addFiles_(success, files);
};
}(), options);
};
TestHarness.reportType = {
ADD_PAGE: 1,
READY: 2,
START_PAGE: 3,
TEST_RESULT: 4,
FINISH_PAGE: 5,
FINISHED_ALL_TESTS: 6
};
TestHarness.prototype.addFiles_ = function(success, files) {
if (!success) {
this.reportFunc(
TestHarness.reportType.FINISHED_ALL_TESTS,
'Unable to load tests. Are you running locally?\n' +
@ -166,24 +360,15 @@ var TestHarness = function(iframe, filelistUrl, reportFunc) {
false)
return;
}
this.files = [];
log("total files: " + files.length);
for (var ii = 0; ii < files.length; ++ii) {
log("" + ii + ": " + files[ii]);
this.files.push(new TestFile(files[ii]));
this.reportFunc(TestHarness.reportType.ADD_PAGE, files[ii], undefined);
}
this.nextFileIndex = files.length;
this.lastFileIndex = files.length;
this.timeoutDelay = 20000;
this.reportFunc(TestHarness.reportType.READY, undefined, undefined);
}
TestHarness.reportType = {
ADD_PAGE: 1,
START_PAGE: 2,
TEST_RESULT: 3,
FINISH_PAGE: 4,
FINISHED_ALL_TESTS: 5
};
TestHarness.prototype.runTests = function(opt_start, opt_count) {
var count = opt_count || this.files.length;
this.nextFileIndex = opt_start || 0;

View File

@ -10,6 +10,12 @@ Mochitest version of the WebGL Conformance Test Suite
<script type="text/javascript" src="resources/webgl-test-harness.js"></script>
<script>
var CONFORMANCE_TEST_VERSION = "1.0.1 (beta)";
var OPTIONS = {
version: CONFORMANCE_TEST_VERSION
};
/**
* This is copied from webgl-test-harness.js where it is defined as a private function, not accessible to us (argh!)
*
@ -266,10 +272,17 @@ function start() {
SimpleTest.finish();
}
Reporter.prototype.ready = function() {
statusTextNode.textContent = 'Loaded test lists. Starting tests...';
window.webglTestHarness.runTests();
}
Reporter.prototype.reportFunc = function(type, msg, success) {
switch (type) {
case reportType.ADD_PAGE:
return this.addPage(msg);
case reportType.READY:
return this.ready();
case reportType.START_PAGE:
return this.startPage(msg);
case reportType.TEST_RESULT:
@ -285,6 +298,25 @@ function start() {
};
};
var getURLOptions = function(obj) {
var s = window.location.href;
var q = s.indexOf("?");
var e = s.indexOf("#");
if (e < 0) {
e = s.length;
}
var query = s.substring(q + 1, e);
var pairs = query.split("&");
for (var ii = 0; ii < pairs.length; ++ii) {
var keyValue = pairs[ii].split("=");
var key = keyValue[0];
var value = decodeURIComponent(keyValue[1]);
obj[key] = value;
}
};
getURLOptions(OPTIONS);
function runTestSuite() {
var reporter = new Reporter();
@ -297,16 +329,17 @@ function start() {
} catch(e) {}
if (ctx) {
statusTextNode.textContent = 'Loading test lists...';
var iframe = document.getElementById("testframe");
var testHarness = new WebGLTestHarnessModule.TestHarness(
iframe,
'00_test_list.txt',
function(type, msg, success) {
return reporter.reportFunc(type, msg, success);
});
},
OPTIONS);
testHarness.setTimeoutDelay(20000); // and make it much higher when running under valgrind.
window.webglTestHarness = testHarness;
testHarness.runTests();
} else {
var errmsg = "Can't create a WebGL context";
reporter.fullResultsNode.textContent = errmsg;

View File

@ -1,236 +0,0 @@
# HG changeset patch
# Parent fb36d18f04ef9b01ca87d3fde539d50c204f9bba
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
@@ -90,190 +90,105 @@ var log = function(msg) {
if (window.console && window.console.log) {
window.console.log(msg);
}
};
/**
* Loads text from an external file. This function is synchronous.
* @param {string} url The url of the external file.
- * @param {!function(bool, string): void} callback that is sent a bool for
- * success and the string.
+ * @return {string} the loaded text if the request is synchronous.
*/
-var loadTextFileAsynchronous = function(url, callback) {
- log ("loading: " + url);
+var loadTextFileSynchronous = function(url) {
var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
if (request.overrideMimeType) {
request.overrideMimeType('text/plain');
}
} else {
throw 'XMLHttpRequest is disabled';
}
- try {
- request.open('GET', url, true);
- request.onreadystatechange = function() {
- if (request.readyState == 4) {
- var text = '';
- // HTTP reports success with a 200 status. The file protocol reports
- // success with zero. HTTP does not use zero as a status code (they
- // start at 100).
- // https://developer.mozilla.org/En/Using_XMLHttpRequest
- var success = request.status == 200 || request.status == 0;
- if (success) {
- text = request.responseText;
- }
- log("loaded: " + url);
- callback(success, text);
- }
- };
- request.send(null);
- } catch (e) {
- log("failed to load: " + url);
- callback(false, '');
+ request.open('GET', url, false);
+ request.send(null);
+ if (request.readyState != 4) {
+ throw error;
}
+ return request.responseText;
};
-var getFileList = function(url, callback) {
+var getFileList = function(url) {
var files = [];
-
- var getFileListImpl = function(url, callback) {
- var files = [];
- if (url.substr(url.length - 4) == '.txt') {
- loadTextFileAsynchronous(url, function() {
- return function(success, text) {
- if (!success) {
- callback(false, '');
- return;
- }
- var lines = text.split('\n');
- var prefix = '';
- var lastSlash = url.lastIndexOf('/');
- if (lastSlash >= 0) {
- prefix = url.substr(0, lastSlash + 1);
- }
- var fail = false;
- var count = 1;
- var index = 0;
- for (var ii = 0; ii < lines.length; ++ii) {
- var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- if (str.length > 4 &&
- str[0] != '#' &&
- str[0] != ";" &&
- str.substr(0, 2) != "//") {
- new_url = prefix + str;
- ++count;
- getFileListImpl(new_url, function(index) {
- return function(success, new_files) {
- log("got files: " + new_files.length);
- if (success) {
- files[index] = new_files;
- }
- finish(success);
- };
- }(index++));
- }
- }
- finish(true);
-
- function finish(success) {
- if (!success) {
- fail = true;
- }
- --count;
- log("count: " + count);
- if (!count) {
- callback(!fail, files);
- }
- }
- }
- }());
-
- } else {
- files.push(url);
- callback(true, files);
+ if (url.substr(url.length - 4) == '.txt') {
+ var lines = loadTextFileSynchronous(url).split('\n');
+ var prefix = '';
+ var lastSlash = url.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ prefix = url.substr(0, lastSlash + 1);
}
- };
-
- getFileListImpl(url, function(success, files) {
- // flatten
- var flat = [];
- flatten(files);
- function flatten(files) {
- for (var ii = 0; ii < files.length; ++ii) {
- var value = files[ii];
- if (typeof(value) == "string") {
- flat.push(value);
- } else {
- flatten(value);
- }
+ for (var ii = 0; ii < lines.length; ++ii) {
+ var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ if (str.length > 4 &&
+ str[0] != '#' &&
+ str[0] != ";" &&
+ str.substr(0, 2) != "//") {
+ new_url = prefix + str;
+ files = files.concat(getFileList(new_url));
}
}
- callback(success, flat);
- });
-};
+ } else {
+ files.push(url);
+ }
+ return files;
+}
var TestFile = function(url) {
this.url = url;
};
var TestHarness = function(iframe, filelistUrl, reportFunc) {
this.window = window;
this.iframe = iframe;
this.reportFunc = reportFunc;
- this.timeoutDelay = 20000;
- this.files = [];
-
- var that = this;
- getFileList(filelistUrl, function() {
- return function(success, files) {
- that.addFiles_(success, files);
- };
- }());
-
-};
-
-TestHarness.reportType = {
- ADD_PAGE: 1,
- READY: 2,
- START_PAGE: 3,
- TEST_RESULT: 4,
- FINISH_PAGE: 5,
- FINISHED_ALL_TESTS: 6
-};
-
-TestHarness.prototype.addFiles_ = function(success, files) {
- if (!success) {
+ try {
+ var files = getFileList(filelistUrl);
+ } catch (e) {
this.reportFunc(
TestHarness.reportType.FINISHED_ALL_TESTS,
'Unable to load tests. Are you running locally?\n' +
'You need to run from a server or configure your\n' +
'browser to allow access to local files (not recommended).\n\n' +
'Note: An easy way to run from a server:\n\n' +
'\tcd path_to_tests\n' +
'\tpython -m SimpleHTTPServer\n\n' +
'then point your browser to ' +
'<a href="http://localhost:8000/webgl-conformance-tests.html">' +
'http://localhost:8000/webgl-conformance-tests.html</a>',
false)
return;
}
- log("total files: " + files.length);
+ this.files = [];
for (var ii = 0; ii < files.length; ++ii) {
- log("" + ii + ": " + files[ii]);
this.files.push(new TestFile(files[ii]));
this.reportFunc(TestHarness.reportType.ADD_PAGE, files[ii], undefined);
}
- this.reportFunc(TestHarness.reportType.READY, undefined, undefined);
this.nextFileIndex = files.length;
this.lastFileIndex = files.length;
+ this.timeoutDelay = 20000;
}
+TestHarness.reportType = {
+ ADD_PAGE: 1,
+ START_PAGE: 2,
+ TEST_RESULT: 3,
+ FINISH_PAGE: 4,
+ FINISHED_ALL_TESTS: 5
+};
+
TestHarness.prototype.runTests = function(opt_start, opt_count) {
var count = opt_count || this.files.length;
this.nextFileIndex = opt_start || 0;
this.lastFileIndex = this.nextFileIndex + count;
this.startNextFile();
};
TestHarness.prototype.setTimeout = function() {

View File

@ -50,6 +50,10 @@ found in the LICENSE file.
<script>
var CONFORMANCE_TEST_VERSION = "1.0.1 (beta)";
var OPTIONS = {
version: CONFORMANCE_TEST_VERSION
};
function start() {
function log(msg) {
@ -217,7 +221,7 @@ function start() {
};
Folder.prototype.checked = function() {
return this.check.checked &&
return this.check.checked &&
(this.folder ? this.folder.checked() : true);
};
@ -247,7 +251,7 @@ function start() {
this.subFolders[name] = subFolder;
this.items.push(subFolder);
this.childUL.appendChild(subFolder.elem);
}
}
return subFolder;
};
@ -363,7 +367,7 @@ function start() {
// generate a text summary
var tx = "";
tx += "WebGL Conformance Test Results\n";
tx += "Version " + CONFORMANCE_TEST_VERSION + "\n";
tx += "Version " + OPTIONS.version + "\n";
tx += "\n";
tx += "-------------------\n\n";
tx += "User Agent: " + (navigator.userAgent ? navigator.userAgent : "(navigator.userAgent is null)") + "\n";
@ -432,7 +436,26 @@ function start() {
};
};
document.getElementById("testVersion").innerHTML = CONFORMANCE_TEST_VERSION;
var getURLOptions = function(obj) {
var s = window.location.href;
var q = s.indexOf("?");
var e = s.indexOf("#");
if (e < 0) {
e = s.length;
}
var query = s.substring(q + 1, e);
var pairs = query.split("&");
for (var ii = 0; ii < pairs.length; ++ii) {
var keyValue = pairs[ii].split("=");
var key = keyValue[0];
var value = decodeURIComponent(keyValue[1]);
obj[key] = value;
}
};
getURLOptions(OPTIONS);
document.getElementById("testVersion").innerHTML = OPTIONS.version;
var reporter = new Reporter();
var iframe = document.getElementById("testframe");
@ -441,7 +464,8 @@ function start() {
'00_test_list.txt',
function(type, msg, success) {
return reporter.reportFunc(type, msg, success);
});
},
OPTIONS);
window.webglTestHarness = testHarness;
var button = document.getElementById("runTestsButton");
button.disabled = true;

View File

@ -207,25 +207,47 @@ static void AppendSubString(nsAString& aString, nsIContent* aContent,
}
#if defined(XP_WIN)
static PRUint32 CountNewlinesIn(nsIContent* aContent, PRUint32 aMaxOffset)
static PRUint32 CountNewlinesInXPLength(nsIContent* aContent,
PRUint32 aXPLength)
{
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text)
return 0;
if (aMaxOffset == PR_UINT32_MAX) {
// search the entire string
aMaxOffset = text->GetLength();
}
NS_ASSERTION(aXPLength == PR_UINT32_MAX || aXPLength <= text->GetLength(),
"text offset is out-of-bounds");
const PRUint32 length = NS_MIN(aXPLength, text->GetLength());
PRUint32 newlines = 0;
for (PRUint32 i = 0; i < aMaxOffset; ++i) {
for (PRUint32 i = 0; i < length; ++i) {
if (text->CharAt(i) == '\n') {
++newlines;
}
}
return newlines;
}
static PRUint32 CountNewlinesInNativeLength(nsIContent* aContent,
PRUint32 aNativeLength)
{
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text) {
return 0;
}
const PRUint32 xpLength = text->GetLength();
PRUint32 newlines = 0;
for (PRUint32 i = 0, nativeOffset = 0;
i < xpLength && nativeOffset < aNativeLength;
++i, ++nativeOffset) {
if (text->CharAt(i) == '\n') {
++newlines;
++nativeOffset;
}
}
return newlines;
}
#endif
static PRUint32 GetNativeTextLength(nsIContent* aContent, PRUint32 aMaxLength = PR_UINT32_MAX)
@ -240,7 +262,7 @@ static PRUint32 GetNativeTextLength(nsIContent* aContent, PRUint32 aMaxLength =
// On Windows, the length of a native newline ("\r\n") is twice the length of
// the XP newline ("\n"), so XP length is equal to the length of the native
// offset plus the number of newlines encountered in the string.
CountNewlinesIn(aContent, aMaxLength);
CountNewlinesInXPLength(aContent, aMaxLength);
#else
// On other platforms, the native and XP newlines are the same.
0;
@ -272,7 +294,7 @@ static PRUint32 ConvertToXPOffset(nsIContent* aContent, PRUint32 aNativeOffset)
// On Windows, the length of a native newline ("\r\n") is twice the length of
// the XP newline ("\n"), so XP offset is equal to the length of the native
// offset minus the number of newlines encountered in the string.
return aNativeOffset - CountNewlinesIn(aContent, aNativeOffset);
return aNativeOffset - CountNewlinesInNativeLength(aContent, aNativeOffset);
#else
// On other platforms, the native and XP newlines are the same.
return aNativeOffset;

View File

@ -300,5 +300,14 @@ _TEST_FILES = \
test_bug694503.html \
$(NULL)
_BROWSER_TEST_FILES = \
browser_bug649778.js \
file_bug649778.html \
file_bug649778.html^headers^ \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,67 @@
// Test for bug 649778 - document.write may cause a document to be written to disk cache even when the page has Cache-Control: no-store
// Globals
var testPath = "http://mochi.test:8888/browser/content/html/content/test/";
var popup;
function checkCache(url, policy, shouldExist)
{
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
getService(Components.interfaces.nsICacheService);
var session = cache.createSession(
"wyciwyg", policy,
Components.interfaces.nsICache.STREAM_BASED);
try {
var cacheEntry = session.openCacheEntry(
url, Components.interfaces.nsICache.ACCESS_READ, true);
is(shouldExist, true, "Entry found");
}
catch (e) {
is(shouldExist, false, "Entry not found");
is(e.result, Components.results.NS_ERROR_CACHE_KEY_NOT_FOUND,
"Invalid error");
}
}
function getPopupURL() {
var sh = popup.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.sessionHistory;
return sh.getEntryAtIndex(sh.index, false).URI.spec;
}
function testContinue() {
var wyciwygURL = getPopupURL();
is(wyciwygURL.substring(0, 10), "wyciwyg://", "Unexpected URL.");
popup.close()
checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_ON_DISK, false);
checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_IN_MEMORY, true);
finish();
}
function waitForWyciwygDocument() {
try {
var url = getPopupURL();
if (url.substring(0, 10) == "wyciwyg://") {
setTimeout(testContinue, 0);
return;
}
}
catch (e) {
}
setTimeout(waitForWyciwygDocument, 100);
}
// Entry point from Mochikit
function test() {
waitForExplicitFinish();
popup = window.open(testPath + "file_bug649778.html", "popup 0",
"height=200,width=200,location=yes," +
"menubar=yes,status=yes,toolbar=yes,dependent=yes");
waitForWyciwygDocument();
}

View File

@ -0,0 +1,11 @@
<html>
<script>
function test() {
document.open();
document.write('<html><body>WYCIWYG DOCUMENT</body></html>');
document.close();
}
</script>
<body onload="setTimeout(test, 0);">
</body>
</html>

View File

@ -0,0 +1 @@
Cache-Control: no-store

View File

@ -136,6 +136,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
#include "nsMimeTypes.h"
#include "nsIRequest.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -1419,6 +1420,7 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
nsCOMPtr<nsIURI> uri = callerDoc->GetDocumentURI();
nsCOMPtr<nsIURI> baseURI = callerDoc->GetBaseURI();
nsCOMPtr<nsIPrincipal> callerPrincipal = callerDoc->NodePrincipal();
nsCOMPtr<nsIChannel> callerChannel = callerDoc->GetChannel();
// We're called from script. Make sure the script is from the same
// origin, not just that the caller can access the document. This is
@ -1490,6 +1492,21 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
rv = channel->SetOwner(callerPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
if (callerChannel) {
nsLoadFlags callerLoadFlags;
rv = callerChannel->GetLoadFlags(&callerLoadFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsLoadFlags loadFlags;
rv = channel->GetLoadFlags(&loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING;
rv = channel->SetLoadFlags(loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
}
// Before we reset the doc notify the globalwindow of the change,
// but only if we still have a window (i.e. our window object the
// current inner window in our outer window).

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