Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-12-01 12:42:09 +01:00
Родитель fb9e7d4ce5 c8926c6aaf
Коммит fe50f7afa0
48 изменённых файлов: 2113 добавлений и 1760 удалений

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

@ -24,48 +24,53 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel
* the panel to the button which triggers it.
* @param {String} [tabId] Identifier of the tab to select when the panel is
* opened. Example: 'rooms', 'contacts', etc.
* @return {Promise}
*/
openCallPanel: function(event, tabId = null) {
let callback = iframe => {
// Helper function to show a specific tab view in the panel.
function showTab() {
if (!tabId) {
return new Promise((resolve) => {
let callback = iframe => {
// Helper function to show a specific tab view in the panel.
function showTab() {
if (!tabId) {
resolve();
return;
}
let win = iframe.contentWindow;
let ev = new win.CustomEvent("UIAction", Cu.cloneInto({
detail: {
action: "selectTab",
tab: tabId
}
}, win));
win.dispatchEvent(ev);
resolve();
}
// If the panel has been opened and initialized before, we can skip waiting
// for the content to load - because it's already there.
if (("contentWindow" in iframe) && iframe.contentWindow.document.readyState == "complete") {
showTab();
return;
}
let win = iframe.contentWindow;
let ev = new win.CustomEvent("UIAction", Cu.cloneInto({
detail: {
action: "selectTab",
tab: tabId
}
}, win));
win.dispatchEvent(ev);
}
iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
injectLoopAPI(iframe.contentWindow);
iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
loopPanelInitialized);
showTab();
});
}, true);
};
// If the panel has been opened and initialized before, we can skip waiting
// for the content to load - because it's already there.
if (("contentWindow" in iframe) && iframe.contentWindow.document.readyState == "complete") {
showTab();
return;
}
// Used to clear the temporary "login" state from the button.
Services.obs.notifyObservers(null, "loop-status-changed", null);
iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
injectLoopAPI(iframe.contentWindow);
iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
loopPanelInitialized);
showTab();
});
}, true);
};
// Used to clear the temporary "login" state from the button.
Services.obs.notifyObservers(null, "loop-status-changed", null);
PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
"loop", null, "about:looppanel", null, callback);
PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
"loop", null, "about:looppanel", null, callback);
});
},
/**

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

@ -64,7 +64,7 @@ function promiseGetMozLoopAPI() {
let frameId = btn.getAttribute("notificationFrameId");
let frame = document.getElementById(frameId);
if (frame) {
loopPanel.removeChild(frame);
frame.remove();
}
});
});

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

@ -111,15 +111,15 @@ this.UITour = {
},
widgetName: "PanelUI-customize",
}],
["devtools", {query: "#developer-button"}],
["help", {query: "#PanelUI-help"}],
["home", {query: "#home-button"}],
["loop", {query: "#loop-button"}],
["devtools", {query: "#developer-button"}],
["webide", {query: "#webide-button"}],
["forget", {
query: "#panic-button",
widgetName: "panic-button",
allowAdd: true }],
allowAdd: true,
}],
["loop", {query: "#loop-button"}],
["privateWindow", {query: "#privatebrowsing-button"}],
["quit", {query: "#PanelUI-quit"}],
["search", {
@ -188,6 +188,7 @@ this.UITour = {
query: "#urlbar",
widgetName: "urlbar-container",
}],
["webide", {query: "#webide-button"}],
]),
init: function() {
@ -714,8 +715,6 @@ this.UITour = {
teardownTour: function(aWindow, aWindowClosing = false) {
log.debug("teardownTour: aWindowClosing = " + aWindowClosing);
aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hidePanelAnnotations);
aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hidePanelAnnotations);
aWindow.removeEventListener("SSWindowClosing", this);
let originTabs = this.originTabs.get(aWindow);
@ -732,8 +731,15 @@ this.UITour = {
this.hideInfo(aWindow);
// Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
this.hideMenu(aWindow, "appMenu");
this.hideMenu(aWindow, "loop");
}
// Clean up panel listeners after we may have called hideMenu above.
aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hidePanelAnnotations);
aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hidePanelAnnotations);
let loopPanel = aWindow.document.getElementById("loop-notification-panel");
loopPanel.removeEventListener("popuphidden", this.onLoopPanelHidden);
this.endUrlbarCapture(aWindow);
this.removePinnedTab(aWindow);
this.resetTheme();
@ -867,7 +873,7 @@ this.UITour = {
*/
_setAppMenuStateForAnnotation: function(aWindow, aAnnotationType, aShouldOpenForHighlight, aCallback = null) {
log.debug("_setAppMenuStateForAnnotation:", aAnnotationType);
log.debug("_setAppMenuStateForAnnotation: Menu is exptected to be:", aShouldOpenForHighlight ? "open" : "closed");
log.debug("_setAppMenuStateForAnnotation: Menu is expected to be:", aShouldOpenForHighlight ? "open" : "closed");
// If the panel is in the desired state, we're done.
let panelIsOpen = aWindow.PanelUI.panel.state != "closed";
@ -1238,6 +1244,26 @@ this.UITour = {
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
openMenuButton(menuBtn);
} else if (aMenuName == "loop") {
let toolbarButton = aWindow.LoopUI.toolbarButton;
if (!toolbarButton || !toolbarButton.node) {
return;
}
let panel = aWindow.document.getElementById("loop-notification-panel");
panel.setAttribute("noautohide", true);
if (panel.state != "open") {
this.recreatePopup(panel);
}
// An event object is expected but we don't want to toggle the panel with a click if the panel
// is already open.
aWindow.LoopUI.openCallPanel({ target: toolbarButton.node, }).then(() => {
if (aOpenCallback) {
aOpenCallback();
}
});
panel.addEventListener("popuphidden", this.onLoopPanelHidden);
} else if (aMenuName == "searchEngines") {
this.getTarget(aWindow, "searchProvider").then(target => {
openMenuButton(target.node);
@ -1258,6 +1284,9 @@ this.UITour = {
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
closeMenuButton(menuBtn);
} else if (aMenuName == "loop") {
let panel = aWindow.document.getElementById("loop-notification-panel");
panel.hidePopup();
} else if (aMenuName == "searchEngines") {
let menuBtn = this.targets.get("searchProvider").query(aWindow.document);
closeMenuButton(menuBtn);
@ -1289,6 +1318,11 @@ this.UITour = {
UITour.appMenuOpenForAnnotation.clear();
},
onLoopPanelHidden: function(aEvent) {
aEvent.target.removeAttribute("noautohide");
UITour.recreatePopup(aEvent.target);
},
recreatePopup: function(aPanel) {
// After changing popup attributes that relate to how the native widget is created
// (e.g. @noautohide) we need to re-create the frame/widget for it to take effect.

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

@ -28,6 +28,8 @@ skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
[browser_UITour_annotation_size_attributes.js]
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly.
[browser_UITour_loop.js]
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly.
[browser_UITour_modalDialog.js]
run-if = os == "mac" # modal dialog disabling only working on OS X
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly

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

@ -89,7 +89,7 @@ let tests = [
yield addPinnedTabPromise();
is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
}),
taskify(function* test_menu() {
taskify(function* test_bookmarks_menu() {
let bookmarksMenuButton = document.getElementById("bookmarks-menu-button");
ise(bookmarksMenuButton.open, false, "Menu should initially be closed");

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

@ -0,0 +1,78 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let gTestTab;
let gContentAPI;
let gContentWindow;
let loopButton;
let loopPanel = document.getElementById("loop-notification-panel");
Components.utils.import("resource:///modules/UITour.jsm");
function test() {
UITourTest();
}
let tests = [
taskify(function* test_menu_show_hide() {
ise(loopButton.open, false, "Menu should initially be closed");
gContentAPI.showMenu("loop");
yield waitForConditionPromise(() => {
return loopButton.open;
}, "Menu should be visible after showMenu()");
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
is(loopPanel.state, "open", "The panel should be open");
ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
gContentAPI.hideMenu("loop");
yield waitForConditionPromise(() => {
return !loopButton.open;
}, "Menu should be hidden after hideMenu()");
checkLoopPanelIsHidden();
}),
// Test the menu was cleaned up in teardown.
taskify(function* setup_menu_cleanup() {
gContentAPI.showMenu("loop");
yield waitForConditionPromise(() => {
return loopButton.open;
}, "Menu should be visible after showMenu()");
// Leave it open so it gets torn down and we can test below that teardown was succesful.
}),
taskify(function* test_menu_cleanup() {
// Test that the open menu from above was torn down fully.
checkLoopPanelIsHidden();
}),
];
function checkLoopPanelIsHidden() {
ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
isnot(loopPanel.state, "open", "The panel shouldn't be open");
is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
}
if (Services.prefs.getBoolPref("loop.enabled")) {
loopButton = window.LoopUI.toolbarButton.node;
registerCleanupFunction(() => {
// Copied from browser/components/loop/test/mochitest/head.js
// Remove the iframe after each test. This also avoids mochitest complaining
// about leaks on shutdown as we intentionally hold the iframe open for the
// life of the application.
let frameId = loopButton.getAttribute("notificationFrameId");
let frame = document.getElementById(frameId);
if (frame) {
frame.remove();
}
});
} else {
ok(true, "Loop is disabled so skip the UITour Loop tests");
tests = [];
}

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

@ -34,7 +34,7 @@ treecol {
}
#category-search > .category-icon {
-moz-image-region: rect(0, 194px, 24px, 168px);
-moz-image-region: rect(0, 192px, 24px, 168px);
}
#category-content > .category-icon {

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

@ -747,6 +747,7 @@ browser.jar:
skin/classic/aero/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
* skin/classic/aero/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/aero/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/aero/browser/devtools/performance.css (devtools/performance.css)
* skin/classic/aero/browser/devtools/timeline.css (devtools/timeline.css)
* skin/classic/aero/browser/devtools/scratchpad.css (devtools/scratchpad.css)
* skin/classic/aero/browser/devtools/shadereditor.css (devtools/shadereditor.css)

4
config/external/moz.build поставляемый
Просмотреть файл

@ -25,9 +25,6 @@ if CONFIG['MOZ_VORBIS']:
if CONFIG['MOZ_TREMOR']:
external_dirs += ['media/libtremor']
if CONFIG['MOZ_OPUS']:
external_dirs += ['media/libopus']
if CONFIG['MOZ_WEBM']:
external_dirs += ['media/libnestegg']
@ -44,6 +41,7 @@ external_dirs += [
'media/kiss_fft',
'media/libcubeb',
'media/libogg',
'media/libopus',
'media/libtheora',
'media/libspeex_resampler',
'media/libstagefright',

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

@ -3852,7 +3852,6 @@ MOZ_TREMOR=
MOZ_WAVE=1
MOZ_SAMPLE_TYPE_FLOAT32=
MOZ_SAMPLE_TYPE_S16=
MOZ_OPUS=1
MOZ_WEBM=1
MOZ_GSTREAMER=
MOZ_DIRECTSHOW=
@ -5224,14 +5223,6 @@ if test "${ac_cv_c_attribute_aligned}" != "0"; then
[${ac_cv_c_attribute_aligned}],[Maximum supported data alignment])
fi
dnl ========================================================
dnl = Disable Opus audio codec support
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(opus,
[ --disable-opus Disable support for Opus audio],
MOZ_OPUS=,
MOZ_OPUS=1)
dnl ========================================================
dnl = Disable VP8 decoder support
dnl ========================================================
@ -5567,10 +5558,6 @@ if test -n "$MOZ_VORBIS" -a -n "$MOZ_TREMOR"; then
AC_MSG_ERROR([MOZ_VORBIS and MOZ_TREMOR are mutually exclusive! The build system should not allow them both to be set, but they are. Please file a bug at https://bugzilla.mozilla.org/])
fi
if test -n "$MOZ_WEBRTC" -a -z "$MOZ_OPUS"; then
AC_MSG_ERROR([MOZ_WEBRTC requires MOZ_OPUS which is disabled.])
fi
if test -n "$MOZ_VORBIS"; then
AC_DEFINE(MOZ_VORBIS)
fi
@ -5581,10 +5568,6 @@ if test -n "$MOZ_TREMOR"; then
MOZ_WEBM_ENCODER=
fi
if test -n "$MOZ_OPUS"; then
AC_DEFINE(MOZ_OPUS)
fi
if test -n "$MOZ_WEBM_ENCODER"; then
AC_DEFINE(MOZ_WEBM_ENCODER)
fi
@ -8877,7 +8860,6 @@ AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
AC_SUBST(MOZ_WAVE)
AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)
AC_SUBST(MOZ_OPUS)
AC_SUBST(MOZ_WEBM)
AC_SUBST(MOZ_WMF)
AC_SUBST(MOZ_FFMPEG)

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

@ -373,7 +373,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_bug338583.html]
# b2g(https not working, bug 907770) b2g-debug(https not working, bug 907770) b2g-desktop(43 total - bug 901343, specialpowers.wrap issue createsystemxhr)
# e10s - bug 970589, bug 1091934
skip-if = buildapp == 'b2g' || toolkit == 'android' || (os == 'linux' && debug && e10s)
skip-if = buildapp == 'b2g' || toolkit == 'android'
[test_bug338679.html]
[test_bug339494.html]
[test_bug339494.xhtml]

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

@ -644,7 +644,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
setTimeout(f, 10 + 10*f.i);
} else {
stress_factor = ((new Date()).getTime()-begin_time)*1/589;
stress_factor *= 1.10; // also, a margin of 10%
stress_factor *= 1.50; // also, a margin of 50%
runAllTests();
}

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

@ -28,6 +28,9 @@ public:
// nsWrapperCache
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla

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

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGL1Context.h"
using namespace mozilla;
bool
WebGL1Context::ValidateAttribPointerType(bool /*integerMode*/, GLenum type, GLsizei* out_alignment, const char* info)
{
MOZ_ASSERT(out_alignment);
if (!out_alignment)
return false;
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
*out_alignment = 1;
return true;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
*out_alignment = 2;
return true;
// XXX case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
*out_alignment = 4;
return true;
}
ErrorInvalidEnumInfo(info, type);
return false;
}

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

@ -35,7 +35,6 @@ public:
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
// -------------------------------------------------------------------------
// Buffer objects - WebGL2ContextBuffers.cpp
@ -126,6 +125,12 @@ public:
void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value);
void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
private:
void VertexAttribI4iv(GLuint index, size_t length, const GLint* v);
void VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v);
public:
// GL 3.0 & ES 3.0
void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
void VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v);
void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
@ -250,11 +255,14 @@ public:
private:
WebGL2Context();
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla

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

@ -56,7 +56,7 @@ SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
return LOCAL_GL_SAMPLES_PASSED;
}
WebGLQueryRefPtr*
WebGLRefPtr<WebGLQuery>*
WebGLContext::GetQueryTargetSlot(GLenum target)
{
switch (target) {

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

@ -5,17 +5,103 @@
#include "WebGL2Context.h"
#include "GLContext.h"
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
using namespace mozilla;
using namespace mozilla::dom;
typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
static inline
GLfloat PuntToFloat(GLint i)
{
fi_t tmp;
tmp.i = i;
return tmp.f;
}
static inline
GLfloat PuntToFloat(GLuint u)
{
fi_t tmp;
tmp.u = u;
return tmp.f;
}
bool
WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info)
{
MOZ_ASSERT(alignment);
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
*alignment = 1;
return true;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
*alignment = 2;
return true;
case LOCAL_GL_INT:
case LOCAL_GL_UNSIGNED_INT:
*alignment = 4;
return true;
}
if (!integerMode) {
switch (type) {
case LOCAL_GL_HALF_FLOAT:
*alignment = 2;
return true;
case LOCAL_GL_FLOAT:
case LOCAL_GL_FIXED:
case LOCAL_GL_INT_2_10_10_10_REV:
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
*alignment = 4;
return true;
}
}
ErrorInvalidEnum("%s: invalid enum value 0x%x", info, type);
return false;
}
// -------------------------------------------------------------------------
// Uniforms and attributes
void
WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (!ValidateAttribIndex(index, "vertexAttribIPointer"))
return;
if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer"))
return;
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->EnsureAttrib(index);
InvalidateBufferFetching();
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
vd.buf = mBoundArrayBuffer;
vd.stride = stride;
vd.size = size;
vd.byteOffset = offset;
vd.type = type;
vd.normalized = false;
vd.integer = true;
MakeContextCurrent();
gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
}
void
@ -141,25 +227,81 @@ WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose
void
WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4i(index, x, y, z, w);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(x);
mVertexAttrib0Vector[1] = PuntToFloat(y);
mVertexAttrib0Vector[2] = PuntToFloat(z);
mVertexAttrib0Vector[3] = PuntToFloat(w);
}
}
void
WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
{
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4iv(index, v);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
}
}
void
WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
{
MOZ_CRASH("Not Implemented.");
VertexAttribI4iv(index, v.Length(), v.Elements());
}
void
WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4ui(index, x, y, z, w);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(x);
mVertexAttrib0Vector[1] = PuntToFloat(y);
mVertexAttrib0Vector[2] = PuntToFloat(z);
mVertexAttrib0Vector[3] = PuntToFloat(w);
}
}
void
WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
{
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4uiv(index, v);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
}
}
void
WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
{
MOZ_CRASH("Not Implemented.");
VertexAttribI4uiv(index, v.Length(), v.Elements());
}
// -------------------------------------------------------------------------

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

@ -52,7 +52,7 @@ class nsIDocShell;
*
* Exceptions: some of the following values are set to higher values than in the spec because
* the values in the spec are ridiculously low. They are explicitly marked below
*/
*/
#define MINVALUE_GL_MAX_TEXTURE_SIZE 1024 // Different from the spec, which sets it to 64 on page 162
#define MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE 512 // Different from the spec, which sets it to 16 on page 162
#define MINVALUE_GL_MAX_VERTEX_ATTRIBS 8 // Page 164
@ -95,8 +95,6 @@ namespace gfx {
class SourceSurface;
}
typedef WebGLRefPtr<WebGLQuery> WebGLQueryRefPtr;
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
@ -134,11 +132,13 @@ TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
class WebGLIntOrFloat {
enum {
Int,
Float
Float,
Uint
} mType;
union {
GLint i;
GLfloat f;
GLuint u;
} mValue;
public:
@ -158,6 +158,7 @@ class WebGLContext
, public nsWrapperCache
, public SupportsWeakPtr<WebGLContext>
{
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureATC;
friend class WebGLExtensionCompressedTextureETC1;
@ -898,10 +899,10 @@ private:
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
WebGLQueryRefPtr* GetQueryTargetSlot(GLenum target);
WebGLRefPtr<WebGLQuery>* GetQueryTargetSlot(GLenum target);
WebGLQueryRefPtr mActiveOcclusionQuery;
WebGLQueryRefPtr mActiveTransformFeedbackQuery;
WebGLRefPtr<WebGLQuery> mActiveOcclusionQuery;
WebGLRefPtr<WebGLQuery> mActiveTransformFeedbackQuery;
// -----------------------------------------------------------------------------
// State and State Requests (WebGLContextState.cpp)
@ -1006,6 +1007,7 @@ private:
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
protected:
inline void InvalidateBufferFetching() {
mBufferFetchingIsVerified = false;
mBufferFetchingHasPerVertex = false;
@ -1192,6 +1194,10 @@ protected:
bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
WebGLTexImageFunc func, WebGLTexDimensions dims);
bool ValidateDrawModeEnum(GLenum mode, const char* info);
bool ValidateAttribIndex(GLuint index, const char* info);
bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
WebGLboolean normalized, GLsizei stride,
WebGLintptr byteOffset, const char* info);
bool ValidateStencilParamsForDrawCall();
bool ValidateGLSLVariableName(const nsAString& name, const char* info);
@ -1329,6 +1335,11 @@ private:
template<class ObjectType>
bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
private:
// -------------------------------------------------------------------------
// Context customization points
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
protected:
int32_t MaxTextureSizeForTarget(TexTarget target) const {
return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize

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

@ -621,12 +621,20 @@ WebGLContext::UndoFakeVertexAttrib0()
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
if (attrib0.integer) {
gl->fVertexAttribIPointer(0,
attrib0.size,
attrib0.type,
attrib0.stride,
reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
} else {
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
}
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}

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

@ -1718,6 +1718,78 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
return true;
}
bool
WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
{
bool valid = (index < MaxVertexAttribs());
if (!valid) {
if (index == GLuint(-1)) {
ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
" probably comes from a getAttribLocation()"
" call, where this return value -1 means"
" that the passed name didn't correspond to"
" an active attribute in the specified"
" program.", info);
} else {
ErrorInvalidValue("%s: `index` must be less than"
" MAX_VERTEX_ATTRIBS.", info);
}
}
return valid;
}
bool
WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
WebGLboolean normalized, GLsizei stride,
WebGLintptr byteOffset, const char* info)
{
WebGLBuffer* buffer = mBoundArrayBuffer;
if (!buffer) {
ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info);
return false;
}
GLsizei requiredAlignment = 0;
if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info))
return false;
// requiredAlignment should always be a power of two
MOZ_ASSERT(IsPOTAssumingNonnegative(requiredAlignment));
GLsizei requiredAlignmentMask = requiredAlignment - 1;
if (size < 1 || size > 4) {
ErrorInvalidValue("%s: invalid element size", info);
return false;
}
// see WebGL spec section 6.6 "Vertex Attribute Data Stride"
if (stride < 0 || stride > 255) {
ErrorInvalidValue("%s: negative or too large stride", info);
return false;
}
if (byteOffset < 0) {
ErrorInvalidValue("%s: negative offset", info);
return false;
}
if (stride & requiredAlignmentMask) {
ErrorInvalidOperation("%s: stride doesn't satisfy the alignment "
"requirement of given type", info);
return false;
}
if (byteOffset & requiredAlignmentMask) {
ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment "
"requirement of given type", info);
return false;
}
return true;
}
bool
WebGLContext::ValidateStencilParamsForDrawCall()
{

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

@ -20,34 +20,13 @@
using namespace mozilla;
using namespace dom;
static bool
CheckAttribIndex(WebGLContext& webgl, GLuint index, const char* info)
{
if (index >= webgl.MaxVertexAttribs()) {
if (index == GLuint(-1)) {
webgl.ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
" probably comes from a getAttribLocation()"
" call, where this return value -1 means"
" that the passed name didn't correspond to"
" an active attribute in the specified"
" program.", info);
} else {
webgl.ErrorInvalidValue("%s: `index` must be less than"
" MAX_VERTEX_ATTRIBS.", info);
}
return false;
}
return true;
}
void
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
{
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib1f"))
if (!ValidateAttribIndex(index, "vertexAttrib1f"))
return;
MakeContextCurrent();
@ -70,7 +49,7 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib2f"))
if (!ValidateAttribIndex(index, "vertexAttrib2f"))
return;
MakeContextCurrent();
@ -93,7 +72,7 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib3f"))
if (!ValidateAttribIndex(index, "vertexAttrib3f"))
return;
MakeContextCurrent();
@ -117,7 +96,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib4f"))
if (!ValidateAttribIndex(index, "vertexAttrib4f"))
return;
MakeContextCurrent();
@ -142,7 +121,7 @@ WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib1fv"))
if (!ValidateAttribIndex(index, "vertexAttrib1fv"))
return;
MakeContextCurrent();
@ -165,7 +144,7 @@ WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib2fv"))
if (!ValidateAttribIndex(index, "vertexAttrib2fv"))
return;
MakeContextCurrent();
@ -188,7 +167,7 @@ WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib3fv"))
if (!ValidateAttribIndex(index, "vertexAttrib3fv"))
return;
MakeContextCurrent();
@ -211,7 +190,7 @@ WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib4fv"))
if (!ValidateAttribIndex(index, "vertexAttrib4fv"))
return;
MakeContextCurrent();
@ -233,7 +212,7 @@ WebGLContext::EnableVertexAttribArray(GLuint index)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "enableVertexAttribArray"))
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
return;
MakeContextCurrent();
@ -252,7 +231,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "disableVertexAttribArray"))
if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
return;
MakeContextCurrent();
@ -273,7 +252,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
if (IsContextLost())
return JS::NullValue();
if (!CheckAttribIndex(*this, index, "getVertexAttrib"))
if (!ValidateAttribIndex(index, "getVertexAttrib"))
return JS::NullValue();
MOZ_ASSERT(mBoundVertexArray);
@ -359,7 +338,7 @@ WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
if (IsContextLost())
return 0;
if (!CheckAttribIndex(*this, index, "getVertexAttribOffset"))
if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
return 0;
if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
@ -380,56 +359,15 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttribPointer"))
if (!ValidateAttribIndex(index, "vertexAttribPointer"))
return;
if (mBoundArrayBuffer == nullptr)
return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
GLsizei requiredAlignment = 1;
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
requiredAlignment = 1;
break;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
requiredAlignment = 2;
break;
// XXX case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
requiredAlignment = 4;
break;
default:
return ErrorInvalidEnumInfo("vertexAttribPointer: type", type);
}
// requiredAlignment should always be a power of two.
GLsizei requiredAlignmentMask = requiredAlignment - 1;
if (!ValidateAttribPointer(false, index, size, type, normalized, stride, byteOffset, "vertexAttribPointer"))
return;
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->EnsureAttrib(index);
if (size < 1 || size > 4)
return ErrorInvalidValue("vertexAttribPointer: invalid element size");
if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
return ErrorInvalidValue("vertexAttribPointer: negative or too large stride");
if (byteOffset < 0)
return ErrorInvalidValue("vertexAttribPointer: negative offset");
if (stride & requiredAlignmentMask) {
return ErrorInvalidOperation("vertexAttribPointer: stride doesn't satisfy the alignment "
"requirement of given type");
}
if (byteOffset & requiredAlignmentMask) {
return ErrorInvalidOperation("vertexAttribPointer: byteOffset doesn't satisfy the alignment "
"requirement of given type");
}
InvalidateBufferFetching();
/* XXX make work with bufferSubData & heterogeneous types
@ -445,11 +383,10 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
vd.byteOffset = byteOffset;
vd.type = type;
vd.normalized = normalized;
vd.integer = false;
MakeContextCurrent();
gl->fVertexAttribPointer(index, size, type, normalized,
stride,
gl->fVertexAttribPointer(index, size, type, normalized, stride,
reinterpret_cast<void*>(byteOffset));
}
@ -459,7 +396,7 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttribDivisor"))
if (!ValidateAttribIndex(index, "vertexAttribDivisor"))
return;
MOZ_ASSERT(mBoundVertexArray);

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

@ -74,6 +74,7 @@ protected:
friend class WebGLContext;
friend class WebGLVertexArrayFake;
friend class WebGL2Context;
};
} // namespace mozilla

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

@ -29,8 +29,13 @@ WebGLVertexArrayFake::BindVertexArrayImpl()
mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, vd.buf);
gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
reinterpret_cast<void*>(vd.byteOffset));
if (vd.integer) {
gl->fVertexAttribIPointer(i, vd.size, vd.type, vd.stride,
reinterpret_cast<const GLvoid*>(vd.byteOffset));
} else {
gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
reinterpret_cast<const GLvoid*>(vd.byteOffset));
}
if (vd.enabled)
gl->fEnableVertexAttribArray(i);

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

@ -25,6 +25,7 @@ struct WebGLVertexAttribData
, type(LOCAL_GL_FLOAT)
, enabled(false)
, normalized(false)
, integer(false)
{}
WebGLRefPtr<WebGLBuffer> buf;
@ -35,6 +36,7 @@ struct WebGLVertexAttribData
GLenum type;
bool enabled;
bool normalized;
bool integer;
GLuint componentSize() const {
switch(type) {

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

@ -42,6 +42,7 @@ UNIFIED_SOURCES += [
UNIFIED_SOURCES += [
'MurmurHash3.cpp',
'WebGL1Context.cpp',
'WebGL1ContextUniforms.cpp',
'WebGL2Context.cpp',
'WebGL2ContextBuffers.cpp',
'WebGL2ContextDraw.cpp',

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

@ -5,6 +5,7 @@
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
setup({allow_uncaught_exception:true});
var errorEvent;
var file;
var line;
@ -31,8 +32,8 @@
generate_tests(assert_equals, [
[ "Event filename", errorEvent.filename, location.href ],
[ "Callback filename", file, location.href ],
[ "Event line number", errorEvent.lineno, 27 ],
[ "Callback line number", line, 27 ],
[ "Event line number", errorEvent.lineno, 28 ],
[ "Callback line number", line, 28 ],
[ "Event message", errorEvent.message, "Error: hello" ],
[ "Callback message", msg, "Error: hello" ],
[ "Event error-object", errorEvent.error, thrown],

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

@ -31,7 +31,7 @@
return tokens;
};
var parse = function (tokens) {
var parse = function (tokens, opt) {
var line = 1;
tokens = tokens.slice();
@ -82,14 +82,41 @@
}
};
var all_ws = function () {
var all_ws = function (store, pea) { // pea == post extended attribute, tpea = same for types
var t = { type: "whitespace", value: "" };
while (true) {
var w = ws();
if (!w) break;
t.value += w.value;
}
if (t.value.length > 0) return t;
if (t.value.length > 0) {
if (store) {
var w = t.value
, re = {
"ws": /^([\t\n\r ]+)/
, "line-comment": /^\/\/(.*)\n?/m
, "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\//
}
, wsTypes = []
;
for (var k in re) wsTypes.push(k);
while (w.length) {
var matched = false;
for (var i = 0, n = wsTypes.length; i < n; i++) {
var type = wsTypes[i];
w = w.replace(re[type], function (tok, m1) {
store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 });
matched = true;
return "";
});
if (matched) break;
}
if (matched) continue;
throw new Error("Surprising white space construct."); // this shouldn't happen
}
}
return t;
}
};
var integer_type = function () {
@ -151,8 +178,15 @@
else if (consume(OTHER, "[")) {
all_ws();
consume(OTHER, "]") || error("Unterminated array type");
if (!obj.array) obj.array = 1;
else obj.array++;
if (!obj.array) {
obj.array = 1;
obj.nullableArray = [obj.nullable];
}
else {
obj.array++;
obj.nullableArray.push(obj.nullable);
}
obj.nullable = false;
}
else return;
}
@ -160,40 +194,46 @@
var single_type = function () {
var prim = primitive_type()
, ret = { sequence: false, nullable: false, array: false, union: false }
, ret = { sequence: false, generic: null, nullable: false, array: false, union: false }
, name
, value
;
if (prim) {
ret.idlType = prim;
}
else if (consume(ID, "sequence")) {
else if (name = consume(ID)) {
value = name.value;
all_ws();
if (!consume(OTHER, "<")) {
ret.idlType = "sequence";
}
else {
ret.sequence = true;
ret.idlType = type() || error("Error parsing sequence type");
// Generic types
if (consume(OTHER, "<")) {
// backwards compat
if (value === "sequence") {
ret.sequence = true;
}
ret.generic = value;
ret.idlType = type() || error("Error parsing generic type " + value);
all_ws();
if (!consume(OTHER, ">")) error("Unterminated sequence");
if (!consume(OTHER, ">")) error("Unterminated generic type " + value);
all_ws();
if (consume(OTHER, "?")) ret.nullable = true;
return ret;
}
else {
ret.idlType = value;
}
}
else {
var name = consume(ID);
if (!name) return;
ret.idlType = name.value;
return;
}
type_suffix(ret);
if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable");
return ret;
};
var union_type = function () {
all_ws();
if (!consume(OTHER, "(")) return;
var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] };
var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] };
var fst = type() || error("Union type with no content");
ret.idlType.push(fst);
while (true) {
@ -211,16 +251,21 @@
return single_type() || union_type();
};
var argument = function () {
var argument = function (store) {
var ret = { optional: false, variadic: false };
ret.extAttrs = extended_attrs();
all_ws();
if (consume(ID, "optional")) {
ret.extAttrs = extended_attrs(store);
all_ws(store, "pea");
var opt_token = consume(ID, "optional");
if (opt_token) {
ret.optional = true;
all_ws();
}
ret.idlType = type();
if (!ret.idlType) return;
if (!ret.idlType) {
if (opt_token) tokens.unshift(opt_token);
return;
}
var type_token = last_token;
if (!ret.optional) {
all_ws();
if (tokens.length >= 3 &&
@ -235,7 +280,12 @@
}
}
all_ws();
var name = consume(ID) || error("No name in argument");
var name = consume(ID);
if (!name) {
if (opt_token) tokens.unshift(opt_token);
tokens.unshift(type_token);
return;
}
ret.name = name.value;
if (ret.optional) {
all_ws();
@ -244,20 +294,33 @@
return ret;
};
var argument_list = function () {
var arg = argument(), ret = [];
if (!arg) return ret;
var argument_list = function (store) {
var ret = []
, arg = argument(store ? ret : null)
;
if (!arg) return;
ret.push(arg);
while (true) {
all_ws();
all_ws(store ? ret : null);
if (!consume(OTHER, ",")) return ret;
all_ws();
var nxt = argument() || error("Trailing comma in arguments list");
var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list");
ret.push(nxt);
}
};
var simple_extended_attr = function () {
var type_pair = function () {
all_ws();
var k = type();
if (!k) return;
all_ws()
if (!consume(OTHER, ",")) return;
all_ws();
var v = type();
if (!v) return;
return [k, v];
};
var simple_extended_attr = function (store) {
all_ws();
var name = consume(ID);
if (!name) return;
@ -274,24 +337,35 @@
}
all_ws();
if (consume(OTHER, "(")) {
ret["arguments"] = argument_list();
var args, pair;
// [Constructor(DOMString str)]
if (args = argument_list(store)) {
ret["arguments"] = args;
}
// [MapClass(DOMString, DOMString)]
else if (pair = type_pair()) {
ret.typePair = pair;
}
// [Constructor()]
else {
ret["arguments"] = [];
}
all_ws();
consume(OTHER, ")") || error("Unclosed argument in extended attribute");
consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair");
}
return ret;
};
// Note: we parse something simpler than the official syntax. It's all that ever
// seems to be used
var extended_attrs = function () {
var extended_attrs = function (store) {
var eas = [];
all_ws();
all_ws(store);
if (!consume(OTHER, "[")) return eas;
eas[0] = simple_extended_attr() || error("Extended attribute with not content");
eas[0] = simple_extended_attr(store) || error("Extended attribute with not content");
all_ws();
while (consume(OTHER, ",")) {
all_ws();
eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute"));
all_ws();
}
consume(OTHER, "]") || error("No end of extended attribute");
@ -314,8 +388,8 @@
}
};
var const_ = function () {
all_ws();
var const_ = function (store) {
all_ws(store, "pea");
if (!consume(ID, "const")) return;
var ret = { type: "const", nullable: false };
all_ws();
@ -352,14 +426,14 @@
}
};
var operation_rest = function (ret) {
var operation_rest = function (ret, store) {
all_ws();
if (!ret) ret = {};
var name = consume(ID);
ret.name = name ? name.value : null;
all_ws();
consume(OTHER, "(") || error("Invalid operation");
ret["arguments"] = argument_list();
ret["arguments"] = argument_list(store) || [];
all_ws();
consume(OTHER, ")") || error("Unterminated operation");
all_ws();
@ -367,8 +441,8 @@
return ret;
};
var callback = function () {
all_ws();
var callback = function (store) {
all_ws(store, "pea");
var ret;
if (!consume(ID, "callback")) return;
all_ws();
@ -387,7 +461,7 @@
ret.idlType = return_type();
all_ws();
consume(OTHER, "(") || error("No arguments in callback");
ret["arguments"] = argument_list();
ret["arguments"] = argument_list(store) || [];
all_ws();
consume(OTHER, ")") || error("Unterminated callback");
all_ws();
@ -395,8 +469,8 @@
return ret;
};
var attribute = function () {
all_ws();
var attribute = function (store) {
all_ws(store, "pea");
var grabbed = []
, ret = {
type: "attribute"
@ -454,8 +528,8 @@
return typ;
};
var operation = function () {
all_ws();
var operation = function (store) {
all_ws(store, "pea");
var ret = {
type: "operation"
, getter: false
@ -478,13 +552,13 @@
if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
all_ws();
ret.idlType = return_type();
operation_rest(ret);
operation_rest(ret, store);
return ret;
}
if (consume(ID, "static")) {
ret["static"] = true;
ret.idlType = return_type();
operation_rest(ret);
operation_rest(ret, store);
return ret;
}
else if (consume(ID, "stringifier")) {
@ -492,7 +566,7 @@
all_ws();
if (consume(OTHER, ";")) return ret;
ret.idlType = return_type();
operation_rest(ret);
operation_rest(ret, store);
return ret;
}
ret.idlType = return_type();
@ -513,7 +587,7 @@
return ret;
}
else {
operation_rest(ret);
operation_rest(ret, store);
return ret;
}
};
@ -530,8 +604,8 @@
}
};
var serialiser = function () {
all_ws();
var serialiser = function (store) {
all_ws(store, "pea");
if (!consume(ID, "serializer")) return;
var ret = { type: "serializer" };
all_ws();
@ -589,77 +663,84 @@
else {
ret.idlType = return_type();
all_ws();
ret.operation = operation_rest();
ret.operation = operation_rest(null, store);
}
return ret;
};
var interface_ = function (isPartial) {
all_ws();
var interface_ = function (isPartial, store) {
all_ws(isPartial ? null : store, "pea");
if (!consume(ID, "interface")) return;
all_ws();
var name = consume(ID) || error("No name for interface");
var ret = {
var mems = []
, ret = {
type: "interface"
, name: name.value
, partial: false
, members: []
, members: mems
};
if (!isPartial) ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless interface");
while (true) {
all_ws();
all_ws(store ? mems : null);
if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after interface");
return ret;
}
var ea = extended_attrs();
var ea = extended_attrs(store ? mems : null);
all_ws();
var cnt = const_();
var cnt = const_(store ? mems : null);
if (cnt) {
cnt.extAttrs = ea;
ret.members.push(cnt);
continue;
}
var mem = serialiser() || attribute() || operation() || error("Unknown member");
var mem = serialiser(store ? mems : null) ||
attribute(store ? mems : null) ||
operation(store ? mems : null) ||
error("Unknown member");
mem.extAttrs = ea;
ret.members.push(mem);
}
};
var partial = function () {
all_ws();
var partial = function (store) {
all_ws(store, "pea");
if (!consume(ID, "partial")) return;
var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
var thing = dictionary(true, store) ||
interface_(true, store) ||
error("Partial doesn't apply to anything");
thing.partial = true;
return thing;
};
var dictionary = function (isPartial) {
all_ws();
var dictionary = function (isPartial, store) {
all_ws(isPartial ? null : store, "pea");
if (!consume(ID, "dictionary")) return;
all_ws();
var name = consume(ID) || error("No name for dictionary");
var ret = {
var mems = []
, ret = {
type: "dictionary"
, name: name.value
, partial: false
, members: []
, members: mems
};
if (!isPartial) ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless dictionary");
while (true) {
all_ws();
all_ws(store ? mems : null);
if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after dictionary");
return ret;
}
var ea = extended_attrs();
all_ws();
var ea = extended_attrs(store ? mems : null);
all_ws(store ? mems : null, "pea");
var typ = type() || error("No type for dictionary member");
all_ws();
var name = consume(ID) || error("No name for dictionary member");
@ -675,28 +756,29 @@
}
};
var exception = function () {
all_ws();
var exception = function (store) {
all_ws(store, "pea");
if (!consume(ID, "exception")) return;
all_ws();
var name = consume(ID) || error("No name for exception");
var ret = {
var mems = []
, ret = {
type: "exception"
, name: name.value
, members: []
, members: mems
};
ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless exception");
while (true) {
all_ws();
all_ws(store ? mems : null);
if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after exception");
return ret;
}
var ea = extended_attrs();
all_ws();
var ea = extended_attrs(store ? mems : null);
all_ws(store ? mems : null, "pea");
var cnt = const_();
if (cnt) {
cnt.extAttrs = ea;
@ -718,21 +800,22 @@
}
};
var enum_ = function () {
all_ws();
var enum_ = function (store) {
all_ws(store, "pea");
if (!consume(ID, "enum")) return;
all_ws();
var name = consume(ID) || error("No name for enum");
var ret = {
var vals = []
, ret = {
type: "enum"
, name: name.value
, values: []
, values: vals
};
all_ws();
consume(OTHER, "{") || error("No curly for enum");
var saw_comma = false;
while (true) {
all_ws();
all_ws(store ? vals : null);
if (consume(OTHER, "}")) {
all_ws();
if (saw_comma) error("Trailing comma in enum");
@ -741,9 +824,10 @@
}
var val = consume(STR) || error("Unexpected value in enum");
ret.values.push(val.value.replace(/"/g, ""));
all_ws();
all_ws(store ? vals : null);
if (consume(OTHER, ",")) {
all_ws();
if (store) vals.push({ type: "," });
all_ws(store ? vals : null);
saw_comma = true;
}
else {
@ -752,15 +836,15 @@
}
};
var typedef = function () {
all_ws();
var typedef = function (store) {
all_ws(store, "pea");
if (!consume(ID, "typedef")) return;
var ret = {
type: "typedef"
};
all_ws();
ret.typeExtAttrs = extended_attrs();
all_ws();
all_ws(store, "tpea");
ret.idlType = type() || error("No type in typedef");
all_ws();
var name = consume(ID) || error("No name in typedef");
@ -770,8 +854,8 @@
return ret;
};
var implements_ = function () {
all_ws();
var implements_ = function (store) {
all_ws(store, "pea");
var target = consume(ID);
if (!target) return;
var w = all_ws();
@ -794,24 +878,24 @@
}
};
var definition = function () {
return callback() ||
interface_() ||
partial() ||
dictionary() ||
exception() ||
enum_() ||
typedef() ||
implements_()
var definition = function (store) {
return callback(store) ||
interface_(false, store) ||
partial(store) ||
dictionary(false, store) ||
exception(store) ||
enum_(store) ||
typedef(store) ||
implements_(store)
;
};
var definitions = function () {
var definitions = function (store) {
if (!tokens.length) return [];
var defs = [];
while (true) {
var ea = extended_attrs()
, def = definition();
var ea = extended_attrs(store ? defs : null)
, def = definition(store ? defs : null);
if (!def) {
if (ea.length) error("Stray extended attributes");
break;
@ -821,21 +905,20 @@
}
return defs;
};
var res = definitions();
var res = definitions(opt.ws);
if (tokens.length) error("Unrecognised tokens");
return res;
};
var obj = {
parse: function (str) {
var tokens = tokenise(str);
return parse(tokens);
}
var inNode = typeof module !== "undefined" && module.exports
, obj = {
parse: function (str, opt) {
if (!opt) opt = {};
var tokens = tokenise(str);
return parse(tokens, opt);
}
};
if (typeof module !== "undefined" && module.exports) {
module.exports = obj;
}
else {
window.WebIDL2 = obj;
}
if (inNode) module.exports = obj;
else window.WebIDL2 = obj;
}());

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

@ -20,6 +20,10 @@ for documentation.
<script>
"use strict";
if (W3CTest.runner) {
W3CTest.runner.requestLongerTimeout(2);
}
runTests();
function runTests() {

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

@ -8,131 +8,7 @@ policies and contribution forms [3].
[3] http://www.w3.org/2004/10/27-testcases
*/
/*
* This file automatically generates browser tests for WebIDL interfaces, using
* the testharness.js framework. To use, first include the following:
*
* <script src=/resources/testharness.js></script>
* <script src=/resources/testharnessreport.js></script>
* <script src=/resources/WebIDLParser.js></script>
* <script src=/resources/idlharness.js></script>
*
* Then you'll need some type of IDLs. Here's some script that can be run on a
* spec written in HTML, which will grab all the elements with class="idl",
* concatenate them, and replace the body so you can copy-paste:
*
var s = "";
[].forEach.call(document.getElementsByClassName("idl"), function(idl) {
//https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
if (!idl.classList.contains("extract"))
{
s += idl.textContent + "\n\n";
}
});
document.body.innerHTML = '<pre></pre>';
document.body.firstChild.textContent = s;
*
* (TODO: write this in Python or something so that it can be done from the
* command line instead.)
*
* Once you have that, put it in your script somehow. The easiest way is to
* embed it literally in an HTML file with <script type=text/plain> or similar,
* so that you don't have to do any escaping. Another possibility is to put it
* in a separate .idl file that's fetched via XHR or similar. Sample usage:
*
* var idl_array = new IdlArray();
* idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
* idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
* idl_array.add_objects({Document: ["document"]});
* idl_array.test();
*
* This tests that window.Document exists and meets all the requirements of
* WebIDL. It also tests that window.document (the result of evaluating the
* string "document") has URL and nodeName properties that behave as they
* should, and otherwise meets WebIDL's requirements for an object whose
* primary interface is Document. It does not test that window.Node exists,
* which is what you want if the Node interface is already tested in some other
* specification's suite and your specification only extends or refers to it.
* Of course, each IDL string can define many different things, and calls to
* add_objects() can register many different objects for different interfaces:
* this is a very simple example.
*
* TODO: Write assert_writable, assert_enumerable, assert_configurable and
* their inverses, and use those instead of just checking
* getOwnPropertyDescriptor.
*
* == Public methods of IdlArray ==
*
* IdlArray objects can be obtained with new IdlArray(). Anything not
* documented in this section should be considered an implementation detail,
* and outside callers should not use it.
*
* add_idls(idl_string):
* Parses idl_string (throwing on parse error) and adds the results to the
* IdlArray. All the definitions will be tested when you run test(). If
* some of the definitions refer to other definitions, those must be present
* too. For instance, if idl_string says that Document inherits from Node,
* the Node interface must also have been provided in some call to add_idls()
* or add_untested_idls().
*
* add_untested_idls(idl_string):
* Like add_idls(), but the definitions will not be tested. If an untested
* interface is added and then extended with a tested partial interface, the
* members of the partial interface will still be tested. Also, all the
* members will still be tested for objects added with add_objects(), because
* you probably want to test that (for instance) window.document has all the
* properties from Node, not just Document, even if the Node interface itself
* is tested in a different test suite.
*
* add_objects(dict):
* dict should be an object whose keys are the names of interfaces or
* exceptions, and whose values are arrays of strings. When an interface or
* exception is tested, every string registered for it with add_objects()
* will be evaluated, and tests will be run on the result to verify that it
* correctly implements that interface or exception. This is the only way to
* test anything about [NoInterfaceObject] interfaces, and there are many
* tests that can't be run on any interface without an object to fiddle with.
*
* The interface has to be the *primary* interface of all the objects
* provided. For example, don't pass {Node: ["document"]}, but rather
* {Document: ["document"]}. Assuming the Document interface was declared to
* inherit from Node, this will automatically test that document implements
* the Node interface too.
*
* Warning: methods will be called on any provided objects, in a manner that
* WebIDL requires be safe. For instance, if a method has mandatory
* arguments, the test suite will try calling it with too few arguments to
* see if it throws an exception. If an implementation incorrectly runs the
* function instead of throwing, this might have side effects, possibly even
* preventing the test suite from running correctly.
*
* prevent_multiple_testing(name):
* This is a niche method for use in case you're testing many objects that
* implement the same interfaces, and don't want to retest the same
* interfaces every single time. For instance, HTML defines many interfaces
* that all inherit from HTMLElement, so the HTML test suite has something
* like
* .add_objects({
* HTMLHtmlElement: ['document.documentElement'],
* HTMLHeadElement: ['document.head'],
* HTMLBodyElement: ['document.body'],
* ...
* })
* and so on for dozens of element types. This would mean that it would
* retest that each and every one of those elements implements HTMLElement,
* Element, and Node, which would be thousands of basically redundant tests.
* The test suite therefore calls prevent_multiple_testing("HTMLElement").
* This means that once one object has been tested to implement HTMLElement
* and its ancestors, no other object will be. Thus in the example code
* above, the harness would test that document.documentElement correctly
* implements HTMLHtmlElement, HTMLElement, Element, and Node; but
* document.head would only be tested for HTMLHeadElement, and so on for
* further objects.
*
* test():
* Run all tests. This should be called after you've called all other
* methods to add IDLs and objects.
*/
/* For user documentation see docs/idlharness.md */
/**
* Notes for people who want to edit this file (not just use it as a library):
@ -550,6 +426,9 @@ IdlArray.prototype.assert_type_is = function(value, type)
return;
case "DOMString":
case "ByteString":
case "USVString":
// TODO: https://github.com/w3c/testharness.js/issues/92
assert_equals(typeof value, "string");
return;
@ -1312,6 +1191,249 @@ IdlInterface.prototype.test_self = function()
}.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
};
//@}
IdlInterface.prototype.test_member_const = function(member)
//@{
{
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
// "For each constant defined on an interface A, there must be
// a corresponding property on the interface object, if it
// exists."
assert_own_property(window[this.name], member.name);
// "The value of the property is that which is obtained by
// converting the constants IDL value to an ECMAScript
// value."
assert_equals(window[this.name][member.name], constValue(member.value),
"property has wrong value");
// "The property has attributes { [[Writable]]: false,
// [[Enumerable]]: true, [[Configurable]]: false }."
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_false(desc.writable, "property is writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_false(desc.configurable, "property is configurable");
}.bind(this), this.name + " interface: constant " + member.name + " on interface object");
// "In addition, a property with the same characteristics must
// exist on the interface prototype object."
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
if (this.has_extended_attribute("Callback")) {
assert_false("prototype" in window[this.name],
this.name + ' should not have a "prototype" property');
return;
}
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
assert_own_property(window[this.name].prototype, member.name);
assert_equals(window[this.name].prototype[member.name], constValue(member.value),
"property has wrong value");
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_false(desc.writable, "property is writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_false(desc.configurable, "property is configurable");
}.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
};
//@}
IdlInterface.prototype.test_member_attribute = function(member)
//@{
{
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
if (member["static"]) {
assert_own_property(window[this.name], member.name,
"The interface object must have a property " +
format_value(member.name));
}
else
{
assert_true(member.name in window[this.name].prototype,
"The prototype object must have a property " +
format_value(member.name));
if (!member.has_extended_attribute("LenientThis")) {
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name];
}.bind(this), "getting property on prototype object must throw TypeError");
} else {
assert_equals(window[this.name].prototype[member.name], undefined,
"getting property on prototype object must return undefined");
}
do_interface_attribute_asserts(window[this.name].prototype, member);
}
}.bind(this), this.name + " interface: attribute " + member.name);
};
//@}
IdlInterface.prototype.test_member_operation = function(member)
//@{
{
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
if (this.has_extended_attribute("Callback")) {
assert_false("prototype" in window[this.name],
this.name + ' should not have a "prototype" property');
return;
}
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
// "For each unique identifier of an operation defined on the
// interface, there must be a corresponding property on the
// interface prototype object (if it is a regular operation) or
// the interface object (if it is a static operation), unless
// the effective overload set for that identifier and operation
// and with an argument count of 0 (for the ECMAScript language
// binding) has no entries."
//
var prototypeOrInterfaceObject;
if (member["static"]) {
assert_own_property(window[this.name], member.name,
"interface prototype object missing static operation");
prototypeOrInterfaceObject = window[this.name];
}
else
{
assert_own_property(window[this.name].prototype, member.name,
"interface prototype object missing non-static operation");
prototypeOrInterfaceObject = window[this.name].prototype;
}
var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceObject, member.name);
// "The property has attributes { [[Writable]]: true,
// [[Enumerable]]: true, [[Configurable]]: true }."
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_true(desc.writable, "property is not writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_true(desc.configurable, "property is not configurable");
// "The value of the property is a Function object whose
// behavior is as follows . . ."
assert_equals(typeof prototypeOrInterfaceObject[member.name], "function",
"property must be a function");
// "The value of the Function objects “length” property is
// a Number determined as follows:
// ". . .
// "Return the length of the shortest argument list of the
// entries in S."
//
// TODO: Doesn't handle overloading or variadic arguments.
assert_equals(prototypeOrInterfaceObject[member.name].length,
member.arguments.filter(function(arg) {
return !arg.optional;
}).length,
"property has wrong .length");
// Make some suitable arguments
var args = member.arguments.map(function(arg) {
return create_suitable_object(arg.idlType);
});
// "Let O be a value determined as follows:
// ". . .
// "Otherwise, throw a TypeError."
// This should be hit if the operation is not static, there is
// no [ImplicitThis] attribute, and the this value is null.
//
// TODO: We currently ignore the [ImplicitThis] case.
if (!member["static"]) {
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name].apply(null, args);
}, "calling operation with this = null didn't throw TypeError");
}
// ". . . If O is not null and is also not a platform object
// that implements interface I, throw a TypeError."
//
// TODO: Test a platform object that implements some other
// interface. (Have to be sure to get inheritance right.)
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name].apply({}, args);
}, "calling operation with this = {} didn't throw TypeError");
}.bind(this), this.name + " interface: operation " + member.name +
"(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
")");
};
//@}
IdlInterface.prototype.test_member_stringifier = function(member)
//@{
{
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
if (this.has_extended_attribute("Callback")) {
assert_false("prototype" in window[this.name],
this.name + ' should not have a "prototype" property');
return;
}
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
// ". . . the property exists on the interface prototype object."
var interfacePrototypeObject = window[this.name].prototype;
assert_own_property(window[this.name].prototype, "toString",
"interface prototype object missing non-static operation");
var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString");
// "The property has attributes { [[Writable]]: B,
// [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the
// stringifier is unforgeable on the interface, and true otherwise."
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_true(desc.writable, "property is not writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_true(desc.configurable, "property is not configurable");
// "The value of the property is a Function object, which behaves as
// follows . . ."
assert_equals(typeof interfacePrototypeObject.toString, "function",
"property must be a function");
// "The value of the Function objects “length” property is the Number
// value 0."
assert_equals(interfacePrototypeObject.toString.length, 0,
"property has wrong .length");
// "Let O be the result of calling ToObject on the this value."
assert_throws(new TypeError(), function() {
window[this.name].prototype.toString.apply(null, []);
}, "calling stringifier with this = null didn't throw TypeError");
// "If O is not an object that implements the interface on which the
// stringifier was declared, then throw a TypeError."
//
// TODO: Test a platform object that implements some other
// interface. (Have to be sure to get inheritance right.)
assert_throws(new TypeError(), function() {
window[this.name].prototype.toString.apply({}, []);
}, "calling stringifier with this = {} didn't throw TypeError");
}.bind(this), this.name + " interface: stringifier");
};
//@}
IdlInterface.prototype.test_members = function()
//@{
@ -1319,195 +1441,37 @@ IdlInterface.prototype.test_members = function()
for (var i = 0; i < this.members.length; i++)
{
var member = this.members[i];
if (member.untested)
{
if (member.untested) {
continue;
}
if (member.type == "const")
{
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
// "For each constant defined on an interface A, there must be
// a corresponding property on the interface object, if it
// exists."
assert_own_property(window[this.name], member.name);
// "The value of the property is that which is obtained by
// converting the constants IDL value to an ECMAScript
// value."
assert_equals(window[this.name][member.name], constValue(member.value),
"property has wrong value");
// "The property has attributes { [[Writable]]: false,
// [[Enumerable]]: true, [[Configurable]]: false }."
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_false(desc.writable, "property is writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_false(desc.configurable, "property is configurable");
}.bind(this), this.name + " interface: constant " + member.name + " on interface object");
// "In addition, a property with the same characteristics must
// exist on the interface prototype object."
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
switch (member.type) {
case "const":
this.test_member_const(member);
break;
if (this.has_extended_attribute("Callback")) {
assert_false("prototype" in window[this.name],
this.name + ' should not have a "prototype" property');
return;
}
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
assert_own_property(window[this.name].prototype, member.name);
assert_equals(window[this.name].prototype[member.name], constValue(member.value),
"property has wrong value");
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_false(desc.writable, "property is writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_false(desc.configurable, "property is configurable");
}.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
}
else if (member.type == "attribute")
{
if (member.has_extended_attribute("Unforgeable"))
{
// We do the checks in test_interface_of instead
continue;
case "attribute":
// For unforgeable attributes, we do the checks in
// test_interface_of instead.
if (!member.has_extended_attribute("Unforgeable")) {
this.test_member_attribute(member);
}
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
break;
if (member["static"]) {
assert_own_property(window[this.name], member.name,
"The interface object must have a property " +
format_value(member.name));
}
else
{
assert_true(member.name in window[this.name].prototype,
"The prototype object must have a property " +
format_value(member.name));
// TODO: Needs to test for LenientThis.
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name];
}.bind(this), "getting property on prototype object must throw TypeError");
do_interface_attribute_asserts(window[this.name].prototype, member);
}
}.bind(this), this.name + " interface: attribute " + member.name);
}
else if (member.type == "operation")
{
case "operation":
// TODO: Need to correctly handle multiple operations with the same
// identifier.
if (!member.name)
{
// Unnamed getter or such
continue;
if (member.name) {
this.test_member_operation(member);
} else if (member.stringifier) {
this.test_member_stringifier(member);
}
test(function()
{
assert_own_property(window, this.name,
"window does not have own property " + format_value(this.name));
break;
if (this.has_extended_attribute("Callback")) {
assert_false("prototype" in window[this.name],
this.name + ' should not have a "prototype" property');
return;
}
assert_own_property(window[this.name], "prototype",
'interface "' + this.name + '" does not have own property "prototype"');
// "For each unique identifier of an operation defined on the
// interface, there must be a corresponding property on the
// interface prototype object (if it is a regular operation) or
// the interface object (if it is a static operation), unless
// the effective overload set for that identifier and operation
// and with an argument count of 0 (for the ECMAScript language
// binding) has no entries."
//
var prototypeOrInterfaceObject;
if (member["static"]) {
assert_own_property(window[this.name], member.name,
"interface prototype object missing static operation");
prototypeOrInterfaceObject = window[this.name];
}
else
{
assert_own_property(window[this.name].prototype, member.name,
"interface prototype object missing non-static operation");
prototypeOrInterfaceObject = window[this.name].prototype;
}
var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceObject, member.name);
// "The property has attributes { [[Writable]]: true,
// [[Enumerable]]: true, [[Configurable]]: true }."
assert_false("get" in desc, "property has getter");
assert_false("set" in desc, "property has setter");
assert_true(desc.writable, "property is not writable");
assert_true(desc.enumerable, "property is not enumerable");
assert_true(desc.configurable, "property is not configurable");
// "The value of the property is a Function object whose
// behavior is as follows . . ."
assert_equals(typeof prototypeOrInterfaceObject[member.name], "function",
"property must be a function");
// "The value of the Function objects “length” property is
// a Number determined as follows:
// ". . .
// "Return the length of the shortest argument list of the
// entries in S."
//
// TODO: Doesn't handle overloading or variadic arguments.
assert_equals(prototypeOrInterfaceObject[member.name].length,
member.arguments.filter(function(arg) {
return !arg.optional;
}).length,
"property has wrong .length");
// Make some suitable arguments
var args = member.arguments.map(function(arg) {
return create_suitable_object(arg.idlType);
});
// "Let O be a value determined as follows:
// ". . .
// "Otherwise, throw a TypeError."
// This should be hit if the operation is not static, there is
// no [ImplicitThis] attribute, and the this value is null.
//
// TODO: We currently ignore the [ImplicitThis] case.
if (!member["static"]) {
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name].apply(null, args);
}, "calling operation with this = null didn't throw TypeError");
}
// ". . . If O is not null and is also not a platform object
// that implements interface I, throw a TypeError."
//
// TODO: Test a platform object that implements some other
// interface. (Have to be sure to get inheritance right.)
assert_throws(new TypeError(), function() {
window[this.name].prototype[member.name].apply({}, args);
}, "calling operation with this = {} didn't throw TypeError");
}.bind(this), this.name + " interface: operation " + member.name +
"(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
")");
default:
// TODO: check more member types.
break;
}
// TODO: check more member types, like stringifier
}
};
@ -1748,11 +1712,14 @@ function do_interface_attribute_asserts(obj, member)
// value 0."
assert_equals(typeof desc.get, "function", "getter must be Function");
assert_equals(desc.get.length, 0, "getter length must be 0");
// TODO: Account for LenientThis
assert_throws(new TypeError(), function()
{
desc.get.call({});
}.bind(this), "calling getter on wrong object type must throw TypeError");
if (!member.has_extended_attribute("LenientThis")) {
assert_throws(new TypeError(), function() {
desc.get.call({});
}.bind(this), "calling getter on wrong object type must throw TypeError");
} else {
assert_equals(desc.get.call({}), undefined,
"calling getter on wrong object type must return undefined");
}
// TODO: Test calling setter on the interface prototype (should throw
// TypeError in most cases).
@ -1774,6 +1741,14 @@ function do_interface_attribute_asserts(obj, member)
{
assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");
assert_equals(desc.set.length, 1, "setter length must be 1");
if (!member.has_extended_attribute("LenientThis")) {
assert_throws(new TypeError(), function() {
desc.set.call({});
}.bind(this), "calling setter on wrong object type must throw TypeError");
} else {
assert_equals(desc.set.call({}), undefined,
"calling setter on wrong object type must return undefined");
}
}
}
//@}
@ -1826,6 +1801,8 @@ function create_suitable_object(type)
return 7;
case "DOMString":
case "ByteString":
case "USVString":
return "foo";
case "object":

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

@ -90,3 +90,18 @@ table#results span.actual {
white-space:pre;
}
span.ok {
color:green;
}
tr.error {
color:red;
}
span.timeout {
color:red;
}
span.ok, span.timeout, span.error {
font-variant:small-caps;
}

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

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

@ -1689,11 +1689,7 @@ MediaDecoder::IsRawEnabled()
bool
MediaDecoder::IsOpusEnabled()
{
#ifdef MOZ_OPUS
return Preferences::GetBool("media.opus.enabled");
#else
return false;
#endif
}
bool

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

@ -12,11 +12,8 @@
#include"GeckoProfiler.h"
#include "OggWriter.h"
#ifdef MOZ_OPUS
#include "OpusTrackEncoder.h"
#endif
#ifdef MOZ_VORBIS
#include "VorbisTrackEncoder.h"
#endif

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

@ -11,12 +11,14 @@ EXPORTS += [
'ContainerWriter.h',
'EncodedFrameContainer.h',
'MediaEncoder.h',
'OpusTrackEncoder.h',
'TrackEncoder.h',
'TrackMetadataBase.h',
]
UNIFIED_SOURCES += [
'MediaEncoder.cpp',
'OpusTrackEncoder.cpp',
'TrackEncoder.cpp',
]
@ -24,10 +26,6 @@ if CONFIG['MOZ_OMX_ENCODER']:
EXPORTS += ['OmxTrackEncoder.h']
UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
if CONFIG['MOZ_OPUS']:
EXPORTS += ['OpusTrackEncoder.h']
UNIFIED_SOURCES += ['OpusTrackEncoder.cpp']
if CONFIG['MOZ_WEBM_ENCODER']:
EXPORTS += ['VorbisTrackEncoder.h',
'VP8TrackEncoder.h',

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

@ -49,10 +49,8 @@ OggCodecState::Create(ogg_page* aPage)
codecState = new TheoraState(aPage);
} else if (aPage->body_len > 6 && memcmp(aPage->body+1, "vorbis", 6) == 0) {
codecState = new VorbisState(aPage);
#ifdef MOZ_OPUS
} else if (aPage->body_len > 8 && memcmp(aPage->body, "OpusHead", 8) == 0) {
codecState = new OpusState(aPage);
#endif
} else if (aPage->body_len > 8 && memcmp(aPage->body, "fishead\0", 8) == 0) {
codecState = new SkeletonState(aPage);
} else {
@ -795,7 +793,6 @@ nsresult VorbisState::ReconstructVorbisGranulepos()
return NS_OK;
}
#ifdef MOZ_OPUS
OpusState::OpusState(ogg_page* aBosPage) :
OggCodecState(aBosPage, true),
mParser(nullptr),
@ -1078,7 +1075,6 @@ bool OpusState::ReconstructOpusGranulepos(void)
mPrevPageGranulepos = last->granulepos;
return true;
}
#endif /* MOZ_OPUS */
SkeletonState::SkeletonState(ogg_page* aBosPage) :
OggCodecState(aBosPage, true),

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

@ -13,14 +13,12 @@
#else
#include <vorbis/codec.h>
#endif
#ifdef MOZ_OPUS
#include <opus/opus.h>
#include "opus/opus_multistream.h"
// For MOZ_SAMPLE_TYPE_*
#include "mozilla/dom/HTMLMediaElement.h"
#include "MediaDecoderStateMachine.h"
#include "MediaDecoderReader.h"
#endif
#include <nsAutoRef.h>
#include <nsDeque.h>
#include <nsTArray.h>
@ -323,7 +321,6 @@ private:
};
class OpusState : public OggCodecState {
#ifdef MOZ_OPUS
public:
explicit OpusState(ogg_page* aBosPage);
virtual ~OpusState();
@ -375,7 +372,6 @@ private:
// where we may need to trim some samples from the end.
int64_t mPrevPageGranulepos;
#endif /* MOZ_OPUS */
};
// Constructs a 32bit version number out of two 16 bit major,minor

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

@ -13,12 +13,10 @@
#include "VideoUtils.h"
#include "theora/theoradec.h"
#include <algorithm>
#ifdef MOZ_OPUS
#include "opus/opus.h"
extern "C" {
#include "opus/opus_multistream.h"
}
#endif
#include "mozilla/dom/TimeRanges.h"
#include "mozilla/TimeStamp.h"
#include "VorbisUtils.h"
@ -62,9 +60,7 @@ static const uint32_t SEEK_FUZZ_USECS = 500000;
// The number of microseconds of "pre-roll" we use for Opus streams.
// The specification recommends 80 ms.
#ifdef MOZ_OPUS
static const int64_t SEEK_OPUS_PREROLL = 80 * USECS_PER_MS;
#endif /* MOZ_OPUS */
enum PageSyncResult {
PAGE_SYNC_ERROR = 1,
@ -136,10 +132,8 @@ OggReader::OggReader(AbstractMediaDecoder* aDecoder)
mMonitor("OggReader"),
mTheoraState(nullptr),
mVorbisState(nullptr),
#ifdef MOZ_OPUS
mOpusState(nullptr),
mOpusEnabled(MediaDecoder::IsOpusEnabled()),
#endif /* MOZ_OPUS */
mSkeletonState(nullptr),
mVorbisSerial(0),
mOpusSerial(0),
@ -183,11 +177,9 @@ nsresult OggReader::ResetDecode(bool start)
if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
res = NS_ERROR_FAILURE;
}
#ifdef MOZ_OPUS
if (mOpusState && NS_FAILED(mOpusState->Reset(start))) {
res = NS_ERROR_FAILURE;
}
#endif /* MOZ_OPUS */
if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
res = NS_ERROR_FAILURE;
}
@ -217,10 +209,8 @@ void OggReader::BuildSerialList(nsTArray<uint32_t>& aTracks)
if (HasAudio()) {
if (mVorbisState) {
aTracks.AppendElement(mVorbisState->mSerial);
#ifdef MOZ_OPUS
} else if (mOpusState) {
aTracks.AppendElement(mOpusState->mSerial);
#endif /* MOZ_OPUS */
}
}
}
@ -359,7 +349,6 @@ void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
mInfo.mAudio.mHasAudio = true;
mInfo.mAudio.mRate = vorbisState->mInfo.rate;
mInfo.mAudio.mChannels = vorbisState->mInfo.channels;
#ifdef MOZ_OPUS
} else if (codecState->GetType() == OggCodecState::TYPE_OPUS) {
OpusState* opusState = static_cast<OpusState*>(codecState);
if (!(mOpusState && mOpusState->mSerial == opusState->mSerial)) {
@ -373,7 +362,6 @@ void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
mInfo.mAudio.mHasAudio = true;
mInfo.mAudio.mRate = opusState->mRate;
mInfo.mAudio.mChannels = opusState->mChannels;
#endif
}
}
}
@ -450,7 +438,6 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
} else {
s->Deactivate();
}
#ifdef MOZ_OPUS
} else if (s->GetType() == OggCodecState::TYPE_OPUS && ReadHeaders(s)) {
if (mOpusEnabled) {
if (!mOpusState) {
@ -464,7 +451,6 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
NS_WARNING("Opus decoding disabled."
" See media.opus.enabled in about:config");
}
#endif // MOZ_OPUS
} else if (s->GetType() == OggCodecState::TYPE_SKELETON && !mSkeletonState) {
mSkeletonState = static_cast<SkeletonState*>(s);
} else {
@ -570,7 +556,7 @@ nsresult OggReader::DecodeVorbis(ogg_packet* aPacket) {
}
return NS_OK;
}
#ifdef MOZ_OPUS
nsresult OggReader::DecodeOpus(ogg_packet* aPacket) {
NS_ASSERTION(aPacket->granulepos != -1, "Must know opus granulepos!");
@ -682,16 +668,12 @@ nsresult OggReader::DecodeOpus(ogg_packet* aPacket) {
return NS_OK;
}
#endif /* MOZ_OPUS */
bool OggReader::DecodeAudioData()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
DebugOnly<bool> haveCodecState = mVorbisState != nullptr
#ifdef MOZ_OPUS
|| mOpusState != nullptr
#endif /* MOZ_OPUS */
;
DebugOnly<bool> haveCodecState = mVorbisState != nullptr ||
mOpusState != nullptr;
NS_ASSERTION(haveCodecState, "Need audio codec state to decode audio");
// Read the next data packet. Skip any non-data packets we encounter.
@ -699,10 +681,8 @@ bool OggReader::DecodeAudioData()
OggCodecState* codecState;
if (mVorbisState)
codecState = static_cast<OggCodecState*>(mVorbisState);
#ifdef MOZ_OPUS
else
codecState = static_cast<OggCodecState*>(mOpusState);
#endif /* MOZ_OPUS */
do {
if (packet) {
OggCodecState::ReleasePacket(packet);
@ -719,10 +699,8 @@ bool OggReader::DecodeAudioData()
nsAutoRef<ogg_packet> autoRelease(packet);
if (mVorbisState) {
DecodeVorbis(packet);
#ifdef MOZ_OPUS
} else if (mOpusState) {
DecodeOpus(packet);
#endif
}
if ((packet->e_o_s) && (!ReadOggChain())) {
@ -749,9 +727,7 @@ void OggReader::SetChained(bool aIsChained) {
bool OggReader::ReadOggChain()
{
bool chained = false;
#ifdef MOZ_OPUS
OpusState* newOpusState = nullptr;
#endif /* MOZ_OPUS */
VorbisState* newVorbisState = nullptr;
nsAutoPtr<MetadataTags> tags;
@ -778,11 +754,9 @@ bool OggReader::ReadOggChain()
if (mVorbisState && (codecState->GetType() == OggCodecState::TYPE_VORBIS)) {
newVorbisState = static_cast<VorbisState*>(codecState.get());
}
#ifdef MOZ_OPUS
else if (mOpusState && (codecState->GetType() == OggCodecState::TYPE_OPUS)) {
newOpusState = static_cast<OpusState*>(codecState.get());
}
#endif
else {
return false;
}
@ -819,7 +793,6 @@ bool OggReader::ReadOggChain()
tags = newVorbisState->GetTags();
}
#ifdef MOZ_OPUS
if ((newOpusState && ReadHeaders(newOpusState)) &&
(mOpusState->mRate == newOpusState->mRate) &&
(mOpusState->mChannels == newOpusState->mChannels)) {
@ -835,7 +808,6 @@ bool OggReader::ReadOggChain()
chained = true;
tags = newOpusState->GetTags();
}
#endif
if (chained) {
SetChained(true);
@ -1441,12 +1413,10 @@ nsresult OggReader::SeekInUnbuffered(int64_t aTarget,
if (HasVideo() && mTheoraState) {
keyframeOffsetMs = mTheoraState->MaxKeyframeOffset();
}
#ifdef MOZ_OPUS
// Add in the Opus pre-roll if necessary, as well.
if (HasAudio() && mOpusState) {
keyframeOffsetMs = std::max(keyframeOffsetMs, SEEK_OPUS_PREROLL);
}
#endif /* MOZ_OPUS */
int64_t seekTarget = std::max(aStartTime, aTarget - keyframeOffsetMs);
// Minimize the bisection search space using the known timestamps from the
// buffered ranges.
@ -1476,11 +1446,9 @@ nsresult OggReader::SeekInternal(int64_t aTarget,
MediaResource* resource = mDecoder->GetResource();
NS_ENSURE_TRUE(resource != nullptr, NS_ERROR_FAILURE);
int64_t adjustedTarget = aTarget;
#ifdef MOZ_OPUS
if (HasAudio() && mOpusState){
adjustedTarget = std::max(aStartTime, aTarget - SEEK_OPUS_PREROLL);
}
#endif /* MOZ_OPUS */
if (adjustedTarget == aStartTime) {
// We've seeked to the media start. Just seek to the offset of the first
@ -1788,10 +1756,8 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
if (HasAudio() && granulepos > 0 && audioTime == -1) {
if (mVorbisState && serial == mVorbisState->mSerial) {
audioTime = mVorbisState->Time(granulepos);
#ifdef MOZ_OPUS
} else if (mOpusState && serial == mOpusState->mSerial) {
audioTime = mOpusState->Time(granulepos);
#endif
}
}
@ -1966,12 +1932,10 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
startTime = VorbisState::Time(&mVorbisInfo, granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
}
#ifdef MOZ_OPUS
else if (mOpusState && serial == mOpusSerial) {
startTime = OpusState::Time(mOpusPreSkip, granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");
}
#endif /* MOZ_OPUS */
else if (mTheoraState && serial == mTheoraSerial) {
startTime = TheoraState::Time(&mTheoraInfo, granulepos);
NS_ASSERTION(startTime > 0, "Must have positive start time");

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

@ -65,11 +65,8 @@ public:
int64_t aTimeThreshold);
virtual bool HasAudio() {
return (mVorbisState != 0 && mVorbisState->mActive)
#ifdef MOZ_OPUS
|| (mOpusState != 0 && mOpusState->mActive)
#endif /* MOZ_OPUS */
;
return (mVorbisState != 0 && mVorbisState->mActive) ||
(mOpusState != 0 && mOpusState->mActive);
}
virtual bool HasVideo() {
@ -285,7 +282,6 @@ private:
// Decode state of the Vorbis bitstream we're decoding, if we have audio.
VorbisState* mVorbisState;
#ifdef MOZ_OPUS
// Decode state of the Opus bitstream we're decoding, if we have one.
OpusState *mOpusState;
@ -293,7 +289,6 @@ private:
// contructor was called. We can't check it dynamically because
// we're not on the main thread;
bool mOpusEnabled;
#endif /* MOZ_OPUS */
// Decode state of the Skeleton bitstream.
SkeletonState* mSkeletonState;

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

@ -169,11 +169,9 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder)
, mContext(nullptr)
, mPacketCount(0)
#ifdef MOZ_OPUS
, mOpusDecoder(nullptr)
, mSkip(0)
, mSeekPreroll(0)
#endif
, mVideoTrack(0)
, mAudioTrack(0)
, mAudioStartUsec(-1)
@ -184,9 +182,7 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
, mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
, mHasVideo(false)
, mHasAudio(false)
#ifdef MOZ_OPUS
, mPaddingDiscarded(false)
#endif
{
MOZ_COUNT_CTOR(WebMReader);
#ifdef PR_LOGGING
@ -304,7 +300,6 @@ nsresult WebMReader::ResetDecode()
// aren't fatal and it fails when ResetDecode is called at a
// time when no vorbis data has been read.
vorbis_synthesis_restart(&mVorbisDsp);
#ifdef MOZ_OPUS
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
if (mOpusDecoder) {
// Reset the decoder.
@ -312,7 +307,6 @@ nsresult WebMReader::ResetDecode()
mSkip = mOpusParser->mPreSkip;
mPaddingDiscarded = false;
}
#endif
}
mVideoPackets.Reset();
@ -514,7 +508,6 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
mInfo.mAudio.mRate = mVorbisDsp.vi->rate;
mInfo.mAudio.mChannels = mVorbisDsp.vi->channels;
#ifdef MOZ_OPUS
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
unsigned char* data = 0;
size_t length = 0;
@ -547,7 +540,6 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
mInfo.mAudio.mChannels = mOpusParser->mChannels;
mSeekPreroll = params.seek_preroll;
#endif
} else {
Cleanup();
return NS_ERROR_FAILURE;
@ -568,7 +560,6 @@ WebMReader::IsMediaSeekable()
return mContext && nestegg_has_cues(mContext);
}
#ifdef MOZ_OPUS
bool WebMReader::InitOpusDecoder()
{
int r;
@ -586,7 +577,6 @@ bool WebMReader::InitOpusDecoder()
return r == OPUS_OK;
}
#endif
bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
{
@ -653,11 +643,9 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
return false;
}
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
#ifdef MOZ_OPUS
if (!DecodeOpus(data, length, aOffset, tstamp_usecs, aPacket)) {
return false;
}
#endif
}
}
@ -739,7 +727,6 @@ bool WebMReader::DecodeVorbis(const unsigned char* aData, size_t aLength,
return true;
}
#ifdef MOZ_OPUS
bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs,
nestegg_packet* aPacket)
@ -876,7 +863,6 @@ bool WebMReader::DecodeOpus(const unsigned char* aData, size_t aLength,
return true;
}
#endif /* MOZ_OPUS */
nsReturnRef<NesteggPacketHolder> WebMReader::NextPacket(TrackType aTrackType)
{

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

@ -24,9 +24,7 @@
#include "vorbis/codec.h"
#endif
#ifdef MOZ_OPUS
#include "OpusParser.h"
#endif
// Holds a nestegg_packet, and its file offset. This is needed so we
// know the offset in the file we've played up to, in order to calculate
@ -190,10 +188,8 @@ public:
MediaTaskQueue* GetTaskQueue() { return mTaskQueue; }
protected:
#ifdef MOZ_OPUS
// Setup opus decoder
bool InitOpusDecoder();
#endif
// Decode a nestegg packet of audio data. Push the audio data on the
// audio queue. Returns true when there's more audio to decode,
@ -205,11 +201,9 @@ protected:
bool DecodeVorbis(const unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs,
int32_t* aTotalFrames);
#ifdef MOZ_OPUS
bool DecodeOpus(const unsigned char* aData, size_t aLength,
int64_t aOffset, uint64_t aTstampUsecs,
nestegg_packet* aPacket);
#endif
// Release context and set to null. Called when an error occurs during
// reading metadata or destruction of the reader itself.
@ -235,13 +229,11 @@ private:
vorbis_block mVorbisBlock;
int64_t mPacketCount;
#ifdef MOZ_OPUS
// Opus decoder state
nsAutoPtr<OpusParser> mOpusParser;
OpusMSDecoder *mOpusDecoder;
uint16_t mSkip; // Samples left to trim before playback.
uint64_t mSeekPreroll; // Nanoseconds to discard after seeking.
#endif
// Queue of video and audio packets that have been read but not decoded. These
// must only be accessed from the state machine thread.
@ -288,12 +280,10 @@ private:
bool mHasVideo;
bool mHasAudio;
#ifdef MOZ_OPUS
// Opus padding should only be discarded on the final packet. Once this
// is set to true, if the reader attempts to decode any further packets it
// will raise an error so we can indicate that the file is invalid.
bool mPaddingDiscarded;
#endif
};
} // namespace mozilla

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

@ -153,7 +153,6 @@ th_info_init
th_packet_isheader
th_packet_iskeyframe
th_setup_free
#ifdef MOZ_OPUS
opus_decoder_create
opus_decoder_destroy
opus_decoder_ctl
@ -172,7 +171,6 @@ opus_encoder_destroy
opus_encoder_ctl
opus_encode
opus_encode_float
#endif
#ifndef MOZ_NATIVE_PNG
MOZ_APNG_get_first_frame_is_hidden
MOZ_APNG_get_next_frame_blend_op

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

@ -3220,10 +3220,10 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex,
srcX = currX + remainingWidth - (srcX - cellRect.x);
destX = currX + remainingWidth - (destX - cellRect.x);
}
Point p1(pc->CSSPixelsToDevPixels(srcX),
pc->CSSPixelsToDevPixels(lineY + mRowHeight / 2));
Point p2(pc->CSSPixelsToDevPixels(destX),
pc->CSSPixelsToDevPixels(lineY + mRowHeight / 2));
Point p1(pc->AppUnitsToGfxUnits(srcX),
pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2));
Point p2(pc->AppUnitsToGfxUnits(destX),
pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2));
SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget);
drawTarget->StrokeLine(p1, p2, colorPatt, strokeOptions);
}
@ -3234,15 +3234,15 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex,
// Paint full vertical line only if we have next sibling.
bool hasNextSibling;
mView->HasNextSibling(currentParent, aRowIndex, &hasNextSibling);
Point p1(pc->CSSPixelsToDevPixels(srcX),
pc->CSSPixelsToDevPixels(lineY));
Point p1(pc->AppUnitsToGfxUnits(srcX),
pc->AppUnitsToGfxUnits(lineY));
Point p2;
p2.x = pc->CSSPixelsToDevPixels(srcX);
p2.x = pc->AppUnitsToGfxUnits(srcX);
if (hasNextSibling)
p2.y = pc->CSSPixelsToDevPixels(lineY + mRowHeight);
p2.y = pc->AppUnitsToGfxUnits(lineY + mRowHeight);
else if (i == level)
p2.y = pc->CSSPixelsToDevPixels(lineY + mRowHeight / 2);
p2.y = pc->AppUnitsToGfxUnits(lineY + mRowHeight / 2);
SnapLineToDevicePixelsForStroking(p1, p2, *drawTarget);
drawTarget->StrokeLine(p1, p2, colorPatt, strokeOptions);

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

@ -276,9 +276,7 @@ pref("media.fragmented-mp4.use-blank-decoder", false);
pref("media.raw.enabled", true);
#endif
pref("media.ogg.enabled", true);
#ifdef MOZ_OPUS
pref("media.opus.enabled", true);
#endif
#ifdef MOZ_WAVE
pref("media.wave.enabled", true);
#endif

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

@ -9,6 +9,7 @@
#include "prlog.h"
#include "RootHashes.inc" // Note: Generated by genRootCAHashes.js
#include "ScopedNSSTypes.h"
#include "mozilla/ArrayUtils.h"
// Note: New CAs will show up as UNKNOWN_ROOT until
// RootHashes.inc is updated to include them. 0 is reserved by

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

@ -2,13 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ['TabEngine', 'TabSetRecord'];
this.EXPORTED_SYMBOLS = ["TabEngine", "TabSetRecord"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const TABS_TTL = 604800; // 7 days
const TABS_TTL = 604800; // 7 days.
const TAB_ENTRIES_LIMIT = 25; // How many URLs to include in tab history.
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -27,7 +26,7 @@ this.TabSetRecord = function TabSetRecord(collection, id) {
TabSetRecord.prototype = {
__proto__: CryptoWrapper.prototype,
_logName: "Sync.Record.Tabs",
ttl: TABS_TTL
ttl: TABS_TTL,
};
Utils.deferGetSet(TabSetRecord, "cleartext", ["clientName", "tabs"]);
@ -36,7 +35,7 @@ Utils.deferGetSet(TabSetRecord, "cleartext", ["clientName", "tabs"]);
this.TabEngine = function TabEngine(service) {
SyncEngine.call(this, "Tabs", service);
// Reset the client on every startup so that we fetch recent tabs
// Reset the client on every startup so that we fetch recent tabs.
this._resetClient();
}
TabEngine.prototype = {
@ -47,7 +46,7 @@ TabEngine.prototype = {
syncPriority: 3,
getChangedIDs: function getChangedIDs() {
getChangedIDs: function () {
// No need for a proper timestamp (no conflict resolution needed).
let changedIDs = {};
if (this._tracker.modified)
@ -55,22 +54,22 @@ TabEngine.prototype = {
return changedIDs;
},
// API for use by Weave UI code to give user choices of tabs to open:
getAllClients: function TabEngine_getAllClients() {
// API for use by Sync UI code to give user choices of tabs to open.
getAllClients: function () {
return this._store._remoteClients;
},
getClientById: function TabEngine_getClientById(id) {
getClientById: function (id) {
return this._store._remoteClients[id];
},
_resetClient: function TabEngine__resetClient() {
_resetClient: function () {
SyncEngine.prototype._resetClient.call(this);
this._store.wipe();
this._tracker.modified = true;
},
removeClientData: function removeClientData() {
removeClientData: function () {
let url = this.engineURL + "/" + this.service.clientsEngine.localID;
this.service.resource(url).delete();
},
@ -94,7 +93,7 @@ function TabStore(name, engine) {
TabStore.prototype = {
__proto__: Store.prototype,
itemExists: function TabStore_itemExists(id) {
itemExists: function (id) {
return id == this.engine.service.clientsEngine.localID;
},
@ -131,23 +130,40 @@ TabStore.prototype = {
continue;
}
// Until we store full or partial history, just grab the current entry.
// index is 1 based, so make sure we adjust.
let entry = tabState.entries[tabState.index - 1];
let acceptable = !filter ? (url) => url :
(url) => url && !filteredUrls.test(url);
// Filter out some urls if necessary. SessionStore can return empty
// tabs in some cases - easiest thing is to just ignore them for now.
if (!entry.url || filter && filteredUrls.test(entry.url)) {
let entries = tabState.entries;
let index = tabState.index;
let current = entries[index - 1];
// We ignore the tab completely if the current entry url is
// not acceptable (we need something accurate to open).
if (!acceptable(current.url)) {
continue;
}
// I think it's also possible that attributes[.image] might not be set
// so handle that as well.
// The element at `index` is the current page. Previous URLs were
// previously visited URLs; subsequent URLs are in the 'forward' stack,
// which we can't represent in Sync, so we truncate here.
let candidates = (entries.length == index) ?
entries :
entries.slice(0, index);
let urls = candidates.map((entry) => entry.url)
.filter(acceptable)
.reverse(); // Because Sync puts current at index 0, and history after.
// Truncate if necessary.
if (urls.length > TAB_ENTRIES_LIMIT) {
urls.length = TAB_ENTRIES_LIMIT;
}
allTabs.push({
title: entry.title || "",
urlHistory: [entry.url],
title: current.title || "",
urlHistory: urls,
icon: tabState.attributes && tabState.attributes.image || "",
lastUsed: Math.floor((tabState.lastAccessed || 0) / 1000)
lastUsed: Math.floor((tabState.lastAccessed || 0) / 1000),
});
}
}
@ -155,7 +171,7 @@ TabStore.prototype = {
return allTabs;
},
createRecord: function createRecord(id, collection) {
createRecord: function (id, collection) {
let record = new TabSetRecord(collection, id);
record.clientName = this.engine.service.clientsEngine.localName;
@ -188,7 +204,7 @@ TabStore.prototype = {
return record;
},
getAllIDs: function TabStore_getAllIds() {
getAllIDs: function () {
// Don't report any tabs if all windows are in private browsing for
// first syncs.
let ids = {};
@ -214,31 +230,38 @@ TabStore.prototype = {
return ids;
},
wipe: function TabStore_wipe() {
wipe: function () {
this._remoteClients = {};
},
create: function TabStore_create(record) {
create: function (record) {
this._log.debug("Adding remote tabs from " + record.clientName);
this._remoteClients[record.id] = record.cleartext;
// Lose some precision, but that's good enough (seconds)
// Lose some precision, but that's good enough (seconds).
let roundModify = Math.floor(record.modified / 1000);
let notifyState = Svc.Prefs.get("notifyTabState");
// If there's no existing pref, save this first modified time
if (notifyState == null)
// If there's no existing pref, save this first modified time.
if (notifyState == null) {
Svc.Prefs.set("notifyTabState", roundModify);
// Don't change notifyState if it's already 0 (don't notify)
else if (notifyState == 0)
return;
// We must have gotten a new tab that isn't the same as last time
else if (notifyState != roundModify)
}
// Don't change notifyState if it's already 0 (don't notify).
if (notifyState == 0) {
return;
}
// We must have gotten a new tab that isn't the same as last time.
if (notifyState != roundModify) {
Svc.Prefs.set("notifyTabState", 0);
}
},
update: function update(record) {
update: function (record) {
this._log.trace("Ignoring tab updates as local ones win");
}
},
};
@ -247,7 +270,7 @@ function TabTracker(name, engine) {
Svc.Obs.add("weave:engine:start-tracking", this);
Svc.Obs.add("weave:engine:stop-tracking", this);
// Make sure "this" pointer is always set correctly for event listeners
// Make sure "this" pointer is always set correctly for event listeners.
this.onTab = Utils.bind2(this, this.onTab);
this._unregisterListeners = Utils.bind2(this, this._unregisterListeners);
}
@ -256,16 +279,17 @@ TabTracker.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
loadChangedIDs: function loadChangedIDs() {
loadChangedIDs: function () {
// Don't read changed IDs from disk at start up.
},
clearChangedIDs: function clearChangedIDs() {
clearChangedIDs: function () {
this.modified = false;
},
_topics: ["pageshow", "TabOpen", "TabClose", "TabSelect"],
_registerListenersForWindow: function registerListenersFW(window) {
_registerListenersForWindow: function (window) {
this._log.trace("Registering tab listeners in window");
for each (let topic in this._topics) {
window.addEventListener(topic, this.onTab, false);
@ -273,11 +297,11 @@ TabTracker.prototype = {
window.addEventListener("unload", this._unregisterListeners, false);
},
_unregisterListeners: function unregisterListeners(event) {
_unregisterListeners: function (event) {
this._unregisterListenersForWindow(event.target);
},
_unregisterListenersForWindow: function unregisterListenersFW(window) {
_unregisterListenersForWindow: function (window) {
this._log.trace("Removing tab listeners in window");
window.removeEventListener("unload", this._unregisterListeners, false);
for each (let topic in this._topics) {
@ -318,7 +342,7 @@ TabTracker.prototype = {
}
},
onTab: function onTab(event) {
onTab: function (event) {
if (event.originalTarget.linkedBrowser) {
let browser = event.originalTarget.linkedBrowser;
if (PrivateBrowsingUtils.isBrowserPrivate(browser) &&
@ -334,7 +358,8 @@ TabTracker.prototype = {
// For page shows, bump the score 10% of the time, emulating a partial
// score. We don't want to sync too frequently. For all other page
// events, always bump the score.
if (event.type != "pageshow" || Math.random() < .1)
if (event.type != "pageshow" || Math.random() < .1) {
this.score += SCORE_INCREMENT_SMALL;
}
},
}
};

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

@ -138,8 +138,16 @@ function mockGetTabState (tab) {
return tab;
}
function mockGetWindowEnumerator(url, numWindows, numTabs) {
function mockGetWindowEnumerator(url, numWindows, numTabs, indexes, moreURLs) {
let elements = [];
function url2entry(url) {
return {
url: ((typeof url == "function") ? url() : url),
title: "title"
};
}
for (let w = 0; w < numWindows; ++w) {
let tabs = [];
let win = {
@ -153,11 +161,8 @@ function mockGetWindowEnumerator(url, numWindows, numTabs) {
for (let t = 0; t < numTabs; ++t) {
tabs.push(TestingUtils.deepCopy({
index: 1,
entries: [{
url: ((typeof url == "string") ? url : url()),
title: "title"
}],
index: indexes ? indexes() : 1,
entries: (moreURLs ? [url].concat(moreURLs()) : [url]).map(url2entry),
attributes: {
image: "image"
},

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

@ -52,23 +52,43 @@ function test_getAllTabs() {
let store = getMockStore();
let tabs;
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://foo.com", 1, 1);
let threeUrls = ["http://foo.com", "http://fuubar.com", "http://barbar.com"];
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://bar.com", 1, 1, () => 2, () => threeUrls);
_("Get all tabs.");
tabs = store.getAllTabs();
_("Tabs: " + JSON.stringify(tabs));
do_check_eq(tabs.length, 1);
do_check_eq(tabs[0].title, "title");
do_check_eq(tabs[0].urlHistory.length, 1);
do_check_eq(tabs[0].urlHistory[0], ["http://foo.com"]);
do_check_eq(tabs[0].urlHistory.length, 2);
do_check_eq(tabs[0].urlHistory[0], "http://foo.com");
do_check_eq(tabs[0].urlHistory[1], "http://bar.com");
do_check_eq(tabs[0].icon, "image");
do_check_eq(tabs[0].lastUsed, 1);
_("Get all tabs, and check that filtering works.");
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "about:foo", 1, 1);
let twoUrls = ["about:foo", "http://fuubar.com"];
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://foo.com", 1, 1, () => 2, () => twoUrls);
tabs = store.getAllTabs(true);
_("Filtered: " + JSON.stringify(tabs));
do_check_eq(tabs.length, 0);
_("Get all tabs, and check that the entries safety limit works.");
let allURLs = [];
for (let i = 0; i < 50; i++) {
allURLs.push("http://foo" + i + ".bar");
}
allURLs.splice(35, 0, "about:foo", "about:bar", "about:foobar");
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://bar.com", 1, 1, () => 45, () => allURLs);
tabs = store.getAllTabs((url) => url.startsWith("about"));
_("Sliced: " + JSON.stringify(tabs));
do_check_eq(tabs.length, 1);
do_check_eq(tabs[0].urlHistory.length, 25);
do_check_eq(tabs[0].urlHistory[0], "http://foo40.bar");
do_check_eq(tabs[0].urlHistory[24], "http://foo16.bar");
}
function test_createRecord() {

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

@ -458,9 +458,7 @@ static nsDefaultMimeTypeEntry defaultMimeEntries [] =
{ VIDEO_OGG, "ogg" },
{ APPLICATION_OGG, "ogg" },
{ AUDIO_OGG, "oga" },
#ifdef MOZ_OPUS
{ AUDIO_OGG, "opus" },
#endif
#ifdef MOZ_WEBM
{ VIDEO_WEBM, "webm" },
{ AUDIO_WEBM, "webm" },