зеркало из https://github.com/mozilla/pjs.git
merge mc into kiwifox
This commit is contained in:
Коммит
8cb1081162
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* CELLS */
|
||||
.cell {
|
||||
outline: 1px dashed #ccc;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
/* SITES */
|
||||
.site {
|
||||
background-color: #ececec;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -70,5 +70,5 @@ JAVAC_FLAGS = \
|
|||
-classpath $(JAVA_CLASSPATH) \
|
||||
-bootclasspath $(JAVA_BOOTCLASSPATH) \
|
||||
-encoding UTF8 \
|
||||
-g \
|
||||
-g:source,lines \
|
||||
$(NULL)
|
||||
|
|
16
configure.in
16
configure.in
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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>
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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",
|
||||
},
|
||||
]);
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
@ -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>
|
|
@ -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");
|
||||
|
|
|
@ -42,7 +42,7 @@ debug("");
|
|||
debug("Canvas.getContext");
|
||||
|
||||
var gl = create3DContext(document.getElementById("canvas"));
|
||||
shouldBeNonNull(gl);
|
||||
shouldBeNonNull("gl");
|
||||
|
||||
function fail(x,y, buf, shouldBe)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
compressed-tex-image.html
|
||||
copy-tex-image-and-sub-image-2d.html
|
||||
gl-pixelstorei.html
|
||||
gl-teximage.html
|
||||
|
|
|
@ -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>
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -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).
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче