Merge m-c to s-c

This commit is contained in:
Philipp von Weitershausen 2011-07-13 15:56:12 -07:00
commit feed89ded5
354 changed files with 7626 additions and 4372 deletions

View File

@ -67,7 +67,7 @@
#include "nsIDocument.h"
#include "nsEventListenerManager.h"
#include "nsIFrame.h"
#include "nsIMenuFrame.h"
#include "nsMenuFrame.h"
#include "nsIHTMLDocument.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISelectionPrivate.h"
@ -688,16 +688,13 @@ nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
return; // Tree with nothing selected
}
#endif
nsIFrame* menuFrame = accessible->GetFrame();
if (!menuFrame)
return;
nsIMenuFrame* imenuFrame = do_QueryFrame(menuFrame);
if (imenuFrame)
nsMenuFrame* menuFrame = do_QueryFrame(accessible->GetFrame());
if (menuFrame)
fireFocus = PR_TRUE;
// QI failed for nsIMenuFrame means it's not on menu bar
if (imenuFrame && imenuFrame->IsOnMenuBar() &&
!imenuFrame->IsOnActiveMenuBar()) {
// QI failed for nsMenuFrame means it's not on menu bar
if (menuFrame && menuFrame->IsOnMenuBar() &&
!menuFrame->IsOnActiveMenuBar()) {
// It is a top level menuitem. Only fire a focus event when the menu bar
// is active.
return;

View File

@ -1,4 +0,0 @@
For information about installing, running and configuring Firefox
including a list of known issues and troubleshooting information,
refer to: http://getfirefox.com/releases/

View File

@ -567,7 +567,7 @@ pref("plugins.hide_infobar_for_missing_plugin", false);
pref("plugins.hide_infobar_for_outdated_plugin", false);
#ifdef XP_MACOSX
pref("plugins.use_layers", false);
pref("plugins.use_layers", true);
pref("plugins.hide_infobar_for_carbon_failure_plugin", false);
#endif

View File

@ -500,3 +500,6 @@ statuspanel[label=""] {
.panel-inner-arrowcontentfooter[footertype="promobox"] {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
}
/* highlighter */
%include highlighter.css

View File

@ -1024,12 +1024,6 @@
#endif
</vbox>
# <iframe id="highlighter-frame"
# transparent="true"
# type="content"
# src="chrome://content/base/highlighter.html"/> is dynamically appended as
# the last child of #tab-view-deck, only when it is needed, for minimal
# performance impact.
# <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
# Introducing the iframe dynamically, as needed, was found to be better than
# starting with an empty iframe here in browser.xul from a Ts standpoint.

View File

@ -0,0 +1,36 @@
#highlighter-container {
pointer-events: none;
}
#highlighter-controls {
position: absolute;
top: 0;
left: 0;
}
#highlighter-veil-container {
overflow: hidden;
}
.highlighter-veil,
#highlighter-veil-middlebox,
#highlighter-veil-transparentbox {
-moz-transition-property: width, height;
-moz-transition-duration: 0.1s;
-moz-transition-timing-function: linear;
}
#highlighter-veil-bottombox,
#highlighter-veil-rightbox {
-moz-box-flex: 1;
}
#highlighter-veil-middlebox:-moz-locale-dir(rtl) {
-moz-box-direction: reverse;
}
#highlighter-close-button {
position: absolute;
pointer-events: auto;
z-index: 1;
}

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Inspector Highlighter code.
-
- The Initial Developer of the Original Code is The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Rob Campbell <rcampbell@mozilla.com> (Original Author)
- Paul Rouget <paul@mozilla.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="chrome://browser/skin/highlighter.css" type="text/css"/>
</head>
<body>
<div id="close-button" role="button" class="clickable"/>
<!--
To darken the page around the selected node, we use black-transparent
divs, organized in 3 rows, keeping the div in the middle transparent.
-->
<div id="veil-container">
<div id="veil">
<div id="veil-topbox" class="veil"/>
<div id="veil-middlebox">
<div id="veil-leftbox" class="veil"/>
<div id="veil-transparentbox"/>
<div id="veil-rightbox" class="veil"/>
</div>
<div id="veil-bottombox" class="veil"/>
</div>
</div>
</body>
</html>

View File

@ -58,9 +58,6 @@ const INSPECTOR_INVISIBLE_ELEMENTS = {
// Inspector notifications dispatched through the nsIObserverService.
const INSPECTOR_NOTIFICATIONS = {
// Fires once the Inspector highlighter is initialized and ready for use.
HIGHLIGHTER_READY: "highlighter-ready",
// Fires once the Inspector highlights an element in the page.
HIGHLIGHTING: "inspector-highlighting",
@ -76,86 +73,153 @@ const INSPECTOR_NOTIFICATIONS = {
};
///////////////////////////////////////////////////////////////////////////
//// IFrameHighlighter
//// Highlighter
/**
* A highlighter mechanism using a transparent xul iframe.
* A highlighter mechanism.
*
* The highlighter is built dynamically once the Inspector is invoked:
* <stack id="highlighter-container">
* <vbox id="highlighter-veil-container">...</vbox>
* <box id="highlighter-controls>...</vbox>
* </stack>
*
* @param nsIDOMNode aBrowser
* The xul:browser object for the content window being highlighted.
*/
function IFrameHighlighter(aBrowser)
function Highlighter(aBrowser)
{
this._init(aBrowser);
}
IFrameHighlighter.prototype = {
Highlighter.prototype = {
_init: function IFH__init(aBrowser)
_init: function Highlighter__init(aBrowser)
{
this.browser = aBrowser;
let stack = this.browser.parentNode;
this.win = this.browser.contentWindow;
this._highlighting = false;
let div = document.createElement("div");
div.flex = 1;
div.setAttribute("style", "pointer-events: none; -moz-user-focus: ignore");
this.highlighterContainer = document.createElement("stack");
this.highlighterContainer.id = "highlighter-container";
let iframe = document.createElement("iframe");
iframe.setAttribute("id", "highlighter-frame");
iframe.setAttribute("transparent", "true");
iframe.setAttribute("type", "content");
iframe.addEventListener("DOMTitleChanged", function(aEvent) {
aEvent.stopPropagation();
}, true);
iframe.flex = 1;
iframe.setAttribute("style", "-moz-user-focus: ignore");
let veilBox = document.createElement("vbox");
veilBox.id = "highlighter-veil-container";
this.listenOnce(iframe, "load", (function iframeLoaded() {
this.iframeDoc = iframe.contentDocument;
let controlsBox = document.createElement("box");
controlsBox.id = "highlighter-controls";
this.veilTopDiv = this.iframeDoc.getElementById("veil-topbox");
this.veilLeftDiv = this.iframeDoc.getElementById("veil-leftbox");
this.veilMiddleDiv = this.iframeDoc.getElementById("veil-middlebox");
this.veilTransparentDiv = this.iframeDoc.getElementById("veil-transparentbox");
// The veil will make the whole page darker except
// for the region of the selected box.
this.buildVeil(veilBox);
let closeButton = this.iframeDoc.getElementById("close-button");
this.listenOnce(closeButton, "click",
InspectorUI.closeInspectorUI.bind(InspectorUI, false), false);
// The controlsBox will host the different interactive
// elements of the highlighter (buttons, toolbars, ...).
this.buildControls(controlsBox);
this.highlighterContainer.appendChild(veilBox);
this.highlighterContainer.appendChild(controlsBox);
stack.appendChild(this.highlighterContainer);
this.browser.addEventListener("resize", this, true);
this.browser.addEventListener("scroll", this, true);
this.browser.addEventListener("click", this, true);
iframe.contentWindow.addEventListener("resize", this, false);
this.handleResize();
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, null);
}).bind(this), true);
},
iframe.setAttribute("src", "chrome://browser/content/highlighter.xhtml");
div.appendChild(iframe);
stack.appendChild(div);
this.iframe = iframe;
this.iframeContainer = div;
/**
* Build the veil:
*
* <vbox id="highlighter-veil-container">
* <box id="highlighter-veil-topbox" class="highlighter-veil"/>
* <hbox id="highlighter-veil-middlebox">
* <box id="highlighter-veil-leftbox" class="highlighter-veil"/>
* <box id="highlighter-veil-transparentbox"/>
* <box id="highlighter-veil-rightbox" class="highlighter-veil"/>
* </hbox>
* <box id="highlighter-veil-bottombox" class="highlighter-veil"/>
* </vbox>
*
* @param nsIDOMNode aParent
*/
buildVeil: function Highlighter_buildVeil(aParent)
{
// We will need to resize these boxes to surround a node.
// See highlightRectangle().
this.veilTopBox = document.createElement("box");
this.veilTopBox.id = "highlighter-veil-topbox";
this.veilTopBox.className = "highlighter-veil";
this.veilMiddleBox = document.createElement("hbox");
this.veilMiddleBox.id = "highlighter-veil-middlebox";
this.veilLeftBox = document.createElement("box");
this.veilLeftBox.id = "highlighter-veil-leftbox";
this.veilLeftBox.className = "highlighter-veil";
this.veilTransparentBox = document.createElement("box");
this.veilTransparentBox.id = "highlighter-veil-transparentbox";
// We don't need any references to veilRightBox and veilBottomBox.
// These boxes are automatically resized (flex=1)
let veilRightBox = document.createElement("box");
veilRightBox.id = "highlighter-veil-rightbox";
veilRightBox.className = "highlighter-veil";
let veilBottomBox = document.createElement("box");
veilBottomBox.id = "highlighter-veil-bottombox";
veilBottomBox.className = "highlighter-veil";
this.veilMiddleBox.appendChild(this.veilLeftBox);
this.veilMiddleBox.appendChild(this.veilTransparentBox);
this.veilMiddleBox.appendChild(veilRightBox);
aParent.appendChild(this.veilTopBox);
aParent.appendChild(this.veilMiddleBox);
aParent.appendChild(veilBottomBox);
},
/**
* Destroy the iframe and its nodes.
* Build the controls:
*
* <box id="highlighter-close-button"/>
*
* @param nsIDOMNode aParent
*/
destroy: function IFH_destroy()
buildControls: function Highlighter_buildControls(aParent)
{
this.browser.removeEventListener("click", this, true);
let closeButton = document.createElement("box");
closeButton.id = "highlighter-close-button";
closeButton.appendChild(document.createElement("image"));
closeButton.setAttribute("onclick", "InspectorUI.closeInspectorUI(false);");
aParent.appendChild(closeButton);
},
/**
* Destroy the nodes.
*/
destroy: function Highlighter_destroy()
{
this.browser.removeEventListener("scroll", this, true);
this.browser.removeEventListener("resize", this, true);
this._highlightRect = null;
this._highlighting = false;
this.veilTopDiv = null;
this.veilLeftDiv = null;
this.veilMiddleDiv = null;
this.veilTransparentDiv = null;
this.veilTopBox = null;
this.veilLeftBox = null;
this.veilMiddleBox = null;
this.veilTransparentBox = null;
this.node = null;
this.iframeDoc = null;
this.browser.parentNode.removeChild(this.iframeContainer);
this.iframeContainer = null;
this.iframe = null;
this.highlighterContainer.parentNode.removeChild(this.highlighterContainer);
this.highlighterContainer = null;
this.win = null
this.browser = null;
},
@ -174,7 +238,7 @@ IFrameHighlighter.prototype = {
* @param boolean aScroll
* Boolean determining whether to scroll or not.
*/
highlight: function IFH_highlight(aScroll)
highlight: function Highlighter_highlight(aScroll)
{
// node is not set or node is not highlightable, bail
if (!this.node || !this.isNodeHighlightable()) {
@ -188,12 +252,6 @@ IFrameHighlighter.prototype = {
left: clientRect.left,
width: clientRect.width,
height: clientRect.height};
let oldRect = this._highlightRect;
if (oldRect && rect.top == oldRect.top && rect.left == oldRect.left &&
rect.width == oldRect.width && rect.height == oldRect.height) {
return; // same rectangle
}
if (aScroll) {
this.node.scrollIntoView();
@ -248,7 +306,7 @@ IFrameHighlighter.prototype = {
* @param object aParams
* extra parameters object
*/
highlightNode: function IFH_highlightNode(aNode, aParams)
highlightNode: function Highlighter_highlightNode(aNode, aParams)
{
this.node = aNode;
this.highlight(aParams && aParams.scroll);
@ -262,16 +320,23 @@ IFrameHighlighter.prototype = {
* @returns boolean
* True if the rectangle was highlighted, false otherwise.
*/
highlightRectangle: function IFH_highlightRectangle(aRect)
highlightRectangle: function Highlighter_highlightRectangle(aRect)
{
let oldRect = this._highlightRect;
if (oldRect && aRect.top == oldRect.top && aRect.left == oldRect.left &&
aRect.width == oldRect.width && aRect.height == oldRect.height) {
return this._highlighting; // same rectangle
}
if (aRect.left >= 0 && aRect.top >= 0 &&
aRect.width > 0 && aRect.height > 0) {
// The bottom div and the right div are flexibles (flex=1).
// We don't need to resize them.
this.veilTopDiv.style.height = aRect.top + "px";
this.veilLeftDiv.style.width = aRect.left + "px";
this.veilMiddleDiv.style.height = aRect.height + "px";
this.veilTransparentDiv.style.width = aRect.width + "px";
this.veilTopBox.style.height = aRect.top + "px";
this.veilLeftBox.style.width = aRect.left + "px";
this.veilMiddleBox.style.height = aRect.height + "px";
this.veilTransparentBox.style.width = aRect.width + "px";
this._highlighting = true;
} else {
@ -286,11 +351,11 @@ IFrameHighlighter.prototype = {
/**
* Clear the highlighter surface.
*/
unhighlight: function IFH_unhighlight()
unhighlight: function Highlighter_unhighlight()
{
this._highlighting = false;
this.veilMiddleDiv.style.height = 0;
this.veilTransparentDiv.style.width = 0;
this.veilMiddleBox.style.height = 0;
this.veilTransparentBox.style.width = 0;
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.UNHIGHLIGHTING, null);
},
@ -305,7 +370,7 @@ IFrameHighlighter.prototype = {
* @returns object
* An object with x and y properties.
*/
midPoint: function IFH_midPoint(aPointA, aPointB)
midPoint: function Highlighter_midPoint(aPointA, aPointB)
{
let pointC = { };
pointC.x = (aPointB.x - aPointA.x) / 2 + aPointA.x;
@ -352,7 +417,7 @@ IFrameHighlighter.prototype = {
* @returns boolean
* True if the node is highlightable or false otherwise.
*/
isNodeHighlightable: function IFH_isNodeHighlightable()
isNodeHighlightable: function Highlighter_isNodeHighlightable()
{
if (!this.node || this.node.nodeType != Node.ELEMENT_NODE) {
return false;
@ -364,29 +429,32 @@ IFrameHighlighter.prototype = {
/////////////////////////////////////////////////////////////////////////
//// Event Handling
attachInspectListeners: function IFH_attachInspectListeners()
attachInspectListeners: function Highlighter_attachInspectListeners()
{
this.browser.addEventListener("mousemove", this, true);
this.browser.addEventListener("click", this, true);
this.browser.addEventListener("dblclick", this, true);
this.browser.addEventListener("mousedown", this, true);
this.browser.addEventListener("mouseup", this, true);
},
detachInspectListeners: function IFH_detachInspectListeners()
detachInspectListeners: function Highlighter_detachInspectListeners()
{
this.browser.removeEventListener("mousemove", this, true);
this.browser.removeEventListener("click", this, true);
this.browser.removeEventListener("dblclick", this, true);
this.browser.removeEventListener("mousedown", this, true);
this.browser.removeEventListener("mouseup", this, true);
},
/**
* Generic event handler.
*
* @param nsIDOMEvent aEvent
* The DOM event object.
*/
handleEvent: function IFH_handleEvent(aEvent)
handleEvent: function Highlighter_handleEvent(aEvent)
{
switch (aEvent.type) {
case "click":
@ -404,46 +472,21 @@ IFrameHighlighter.prototype = {
aEvent.stopPropagation();
aEvent.preventDefault();
break;
case "scroll":
this.highlight();
break;
}
},
/**
* Handle clicks on the iframe.
* Handle clicks.
*
* @param nsIDOMEvent aEvent
* The DOM event.
*/
handleClick: function IFH_handleClick(aEvent)
handleClick: function Highlighter_handleClick(aEvent)
{
// Proxy the click event to the iframe.
let x = aEvent.clientX;
let y = aEvent.clientY;
let frameWin = aEvent.view;
while (frameWin != this.win) {
if (frameWin.frameElement) {
let frameRect = frameWin.frameElement.getBoundingClientRect();
x += frameRect.left;
y += frameRect.top;
}
frameWin = frameWin.parent;
}
let element = this.iframeDoc.elementFromPoint(x, y);
if (element && element.classList &&
element.classList.contains("clickable")) {
let newEvent = this.iframeDoc.createEvent("MouseEvents");
newEvent.initMouseEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable,
this.iframeDoc.defaultView, aEvent.detail, aEvent.screenX,
aEvent.screenY, x, y, aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
aEvent.metaKey, aEvent.button, null);
element.dispatchEvent(newEvent);
aEvent.preventDefault();
aEvent.stopPropagation();
return;
}
// Stop inspection when the user clicks on a node.
if (InspectorUI.inspecting) {
if (aEvent.button == 0) {
let win = aEvent.target.ownerDocument.defaultView;
InspectorUI.stopInspecting();
@ -451,7 +494,6 @@ IFrameHighlighter.prototype = {
}
aEvent.preventDefault();
aEvent.stopPropagation();
}
},
/**
@ -460,12 +502,8 @@ IFrameHighlighter.prototype = {
* @param nsiDOMEvent aEvent
* The MouseEvent triggering the method.
*/
handleMouseMove: function IFH_handleMouseMove(aEvent)
handleMouseMove: function Highlighter_handleMouseMove(aEvent)
{
if (!InspectorUI.inspecting) {
return;
}
let element = InspectorUI.elementFromPoint(aEvent.target.ownerDocument,
aEvent.clientX, aEvent.clientY);
if (element && element != this.node) {
@ -476,69 +514,10 @@ IFrameHighlighter.prototype = {
/**
* Handle window resize events.
*/
handleResize: function IFH_handleResize()
handleResize: function Highlighter_handleResize()
{
let style = this.iframeContainer.style;
if (this.win.scrollMaxY && this.win.scrollbars.visible) {
style.paddingRight = this.getScrollbarWidth() + "px";
} else {
style.paddingRight = 0;
}
if (this.win.scrollMaxX && this.win.scrollbars.visible) {
style.paddingBottom = this.getScrollbarWidth() + "px";
} else {
style.paddingBottom = 0;
}
this.highlight();
},
/**
* Determine the scrollbar width in the current document.
*
* @returns number
* The scrollbar width in pixels.
*/
getScrollbarWidth: function IFH_getScrollbarWidth()
{
if (this._scrollbarWidth) {
return this._scrollbarWidth;
}
let hbox = document.createElement("hbox");
hbox.setAttribute("style", "height: 0%; overflow: hidden");
let scrollbar = document.createElement("scrollbar");
scrollbar.setAttribute("orient", "vertical");
hbox.appendChild(scrollbar);
document.documentElement.appendChild(hbox);
this._scrollbarWidth = scrollbar.clientWidth;
document.documentElement.removeChild(hbox);
return this._scrollbarWidth;
},
/**
* Helper to listen for an event only once.
*
* @param nsIDOMEventTarget aTarget
* The DOM event target you want to add an event listener to.
* @param string aName
* The event name you want to listen for.
* @param function aCallback
* The function you want to execute once for the given event.
* @param boolean aCapturing
* Tells if you want to use capture for the event listener.
* @returns void
*/
listenOnce: function IFH_listenOnce(aTarget, aName, aCallback, aCapturing)
{
aTarget.addEventListener(aName, function listenOnce_handler(aEvent) {
aTarget.removeEventListener(aName, listenOnce_handler, aCapturing);
aCallback.call(this, aEvent);
}, aCapturing);
},
};
///////////////////////////////////////////////////////////////////////////
@ -785,7 +764,6 @@ var InspectorUI = {
this.openTreePanel();
this.browser.addEventListener("scroll", this, true);
this.inspectCmd.setAttribute("checked", true);
},
@ -794,9 +772,8 @@ var InspectorUI = {
*/
initializeHighlighter: function IUI_initializeHighlighter()
{
Services.obs.addObserver(this.highlighterReady,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, false);
this.highlighter = new IFrameHighlighter(this.browser);
this.highlighter = new Highlighter(this.browser);
this.highlighterReady();
},
/**
@ -857,7 +834,6 @@ var InspectorUI = {
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
}
this.browser.removeEventListener("scroll", this, true);
this.stopInspecting();
if (this.highlighter) {
this.highlighter.destroy();
@ -953,7 +929,7 @@ var InspectorUI = {
/////////////////////////////////////////////////////////////////////////
//// Event Handling
notifyReady: function IUI_notifyReady()
highlighterReady: function IUI_highlighterReady()
{
// Setup the InspectorStore or restore state
this.initializeStore();
@ -966,13 +942,6 @@ var InspectorUI = {
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.OPENED, null);
},
highlighterReady: function IUI_highlighterReady()
{
Services.obs.removeObserver(InspectorUI.highlighterReady,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, false);
InspectorUI.notifyReady();
},
/**
* Main callback handler for events.
*
@ -1040,9 +1009,6 @@ var InspectorUI = {
break;
}
break;
case "scroll":
this.highlighter.highlight();
break;
}
},

View File

@ -867,7 +867,8 @@
updatePageReport = true;
newBrowser.setAttribute("type", "content-primary");
newBrowser.docShellIsActive = true;
newBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
this.showTab(this.mCurrentTab);
@ -2463,6 +2464,12 @@
case "keypress":
this._handleKeyEvent(aEvent);
break;
case "sizemodechange":
if (aEvent.target == window) {
this.mCurrentBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
}
break;
}
]]></body>
</method>
@ -2472,6 +2479,7 @@
this.mCurrentBrowser = this.mPanelContainer.childNodes[0].firstChild.firstChild;
this.mCurrentTab = this.tabContainer.firstChild;
document.addEventListener("keypress", this, false);
window.addEventListener("sizemodechange", this, false);
var uniqueId = "panel" + Date.now();
this.mPanelContainer.childNodes[0].id = uniqueId;
@ -2534,6 +2542,7 @@
this.mTabListeners[i] = null;
}
document.removeEventListener("keypress", this, false);
window.removeEventListener("sizemodechange", this, false);
]]>
</destructor>

View File

@ -256,6 +256,7 @@ _BROWSER_FILES = \
browser_addon_bar_shortcut.js \
browser_addon_bar_aomlistener.js \
test_bug628179.html \
browser_minimize.js \
$(NULL)
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))

View File

@ -41,8 +41,10 @@ var progressListener4 = {
onLocationChange: function onLocationChange() {
ok(expectListener4, "didn't call progressListener4 for the first location change");
gBrowser.removeProgressListener(this);
executeSoon(function () {
gBrowser.addTab();
gBrowser.removeCurrentTab();
finish();
});
}
};

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function waitForActive() {
if (!gBrowser.docShell.isActive) {
executeSoon(waitForActive);
return;
}
is(gBrowser.docShell.isActive, true, "Docshell should be active again");
finish();
}
function waitForInactive() {
if (gBrowser.docShell.isActive) {
executeSoon(waitForInactive);
return;
}
is(gBrowser.docShell.isActive, false, "Docshell should be inactive");
window.restore();
waitForActive();
}
function test() {
waitForExplicitFinish();
is(gBrowser.docShell.isActive, true, "Docshell should be active");
window.minimize();
// XXX On Linux minimize/restore seem to be very very async, but
// our window.windowState changes sync.... so we can't rely on the
// latter correctly reflecting the state of the former. In
// particular, a restore() call before minimizing is done will not
// actually restore the window, but change the window state. As a
// result, just poll waiting for our expected isActive values.
waitForInactive();
}

View File

@ -110,9 +110,11 @@ function runNextTest() {
let onHidden = onHiddenArray.shift();
info("[Test #" + gTestIndex + "] popup hidden (" + onHiddenArray.length + " hides remaining)");
executeSoon(function () {
onHidden.call(nextTest, this);
if (!onHiddenArray.length)
goNext();
});
}, onHiddenArray.length);
info("[Test #" + gTestIndex + "] added listeners; panel state: " + PopupNotifications.isPanelOpen);
}

View File

@ -30,7 +30,6 @@ browser.jar:
* content/browser/browser.xul (content/browser.xul)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
* content/browser/fullscreen-video.xhtml (content/fullscreen-video.xhtml)
content/browser/highlighter.xhtml (content/highlighter.xhtml)
* content/browser/inspector.html (content/inspector.html)
* content/browser/scratchpad.xul (content/scratchpad.xul)
* content/browser/scratchpad.js (content/scratchpad.js)

View File

@ -84,13 +84,17 @@ var gTabsListener = {
// Reset arrays.
this._loadedURIs.length = 0;
this._openTabsCount = 0;
executeSoon(function () {
// Close all tabs.
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
this._openTabsCount = 0;
// Test finished. This will move to the next one.
waitForFocus(gCurrentTest.finish, gBrowser.ownerDocument.defaultView);
});
}
}
}

View File

@ -101,7 +101,6 @@
#else
@BINPATH@/mozsqlt3@DLL_SUFFIX@
#endif
@BINPATH@/README.txt
@BINPATH@/blocklist.xml
#ifdef XP_UNIX
@BINPATH@/run-mozilla.sh

View File

@ -229,6 +229,7 @@ install.rdf
modules/JSON.jsm
mozilla-runtime@BIN_SUFFIX@
old-homepage-default.properties
README.txt
res/arrow.gif
res/arrowd.gif
res/broken-image.gif

View File

@ -125,8 +125,6 @@ install::
$(LOCALE_SRCDIR)/existing-profile-defaults.js > $(DESTDIR)$(mozappdir)/defaults/existing-profile-defaults.js; \
fi
README_FILE = $(call MERGE_FILE,README.txt)
PROFILE_FILES = \
localstore.rdf \
mimeTypes.rdf \
@ -134,18 +132,6 @@ PROFILE_FILES = \
PROFILE_CHROME = userChrome-example.css userContent-example.css
libs:: $(README_FILE)
ifeq ($(OS_ARCH),WINNT)
$(EXIT_ON_ERROR) \
for file in $^; do \
$(PERL) -pe 's/(?<!\r)\n/\r\n/g;' < $$file > $(FINAL_TARGET)/`basename $$file`; \
done
else
ifneq ($(OS_ARCH),OS2)
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)
endif
endif
NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD))
%/defaults/profile/bookmarks.html: bookmarks.inc generic/profile/bookmarks.html.in

View File

@ -1,4 +0,0 @@
For information about installing, running and configuring Firefox
including a list of known issues and troubleshooting information,
refer to: http://getfirefox.com/releases/

View File

@ -98,7 +98,6 @@ if [ "$ENABLE_TESTS" ]; then
browser/components/places/tests/Makefile
browser/components/places/tests/chrome/Makefile
browser/components/places/tests/browser/Makefile
browser/components/places/tests/perf/Makefile
browser/components/privatebrowsing/test/Makefile
browser/components/privatebrowsing/test/browser/Makefile
browser/components/safebrowsing/content/test/Makefile

View File

@ -1935,3 +1935,27 @@ panel[dimmed="true"] {
border-top-left-radius: .3em;
margin-left: 1em;
}
/* Highlighter */
.highlighter-veil {
background-color: rgba(0, 0, 0, 0.5);
}
#highlighter-close-button {
list-style-image: url("chrome://browser/skin/KUI-close.png");
top: 12px;
right: 12px;
cursor: pointer;
}
#highlighter-close-button:-moz-locale-dir(rtl) {
right: auto;
left: 12px;
}
#highlighter-veil-transparentbox {
box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
outline: 1px dashed rgba(255,255,255,0.5);
outline-offset: -1px;
}

View File

@ -1,104 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Paul Rouget <paul@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
body {
margin: 0;
overflow: hidden;
}
#close-button {
background-image: url("KUI-close.png");
border: none;
padding: 0;
width: 24px;
height: 24px;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
cursor: pointer;
}
.veil {
background-color: rgba(0, 0, 0, 0.5);
}
.veil, #veil-middlebox, #veil-transparentbox {
-moz-transition: 0.1s;
-moz-transition-timing-function: linear;
}
#veil-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#veil {
width: 100%;
height: 100%;
display: -moz-box;
-moz-box-orient: vertical;
}
#veil-topbox, #veil-bottombox {
width: 100%;
}
#veil-bottombox {
-moz-box-flex: 1;
}
#veil-middlebox {
display: -moz-box;
-moz-box-orient: horizontal;
}
#veil-leftbox, #veil-rightbox {
height: 100%;
}
#veil-rightbox {
-moz-box-flex: 1;
}
#veil {
vertical-align: top;
}

View File

@ -17,7 +17,6 @@ browser.jar:
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Go-arrow.png
* skin/classic/browser/highlighter.css
skin/classic/browser/identity.png
skin/classic/browser/Info.png
skin/classic/browser/KUI-close.png

View File

@ -2508,3 +2508,28 @@ panel[dimmed="true"] {
border-top-left-radius: .3em;
margin-left: 1em;
}
/* Highlighter */
.highlighter-veil {
background-color: rgba(0, 0, 0, 0.5);
}
#highlighter-close-button {
list-style-image: url("chrome://browser/skin/KUI-close.png");
top: 12px;
right: 12px;
cursor: pointer;
}
#highlighter-close-button:-moz-locale-dir(rtl) {
right: auto;
left: 12px;
}
#highlighter-veil-transparentbox {
box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
outline: 1px dashed rgba(255,255,255,0.5);
outline-offset: -1px;
}

View File

@ -15,7 +15,6 @@ browser.jar:
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Go-arrow.png
* skin/classic/browser/highlighter.css
skin/classic/browser/home.png
skin/classic/browser/hud-style-check-box-checked.png
skin/classic/browser/hud-style-check-box-empty.png

View File

@ -2434,3 +2434,27 @@ panel[dimmed="true"] {
border-top-left-radius: .3em;
margin-left: 1em;
}
/* Highlighter */
.highlighter-veil {
background-color: rgba(0, 0, 0, 0.5);
}
#highlighter-close-button {
list-style-image: url("chrome://browser/skin/KUI-close.png");
top: 12px;
right: 12px;
cursor: pointer;
}
#highlighter-close-button:-moz-locale-dir(rtl) {
right: auto;
left: 12px;
}
#highlighter-veil-transparentbox {
box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
outline: 1px dashed rgba(255,255,255,0.5);
outline-offset: -1px;
}

View File

@ -1,105 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Paul Rouget <paul@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
body {
margin: 0;
overflow: hidden;
}
#close-button {
background-image: url("KUI-close.png");
border: none;
padding: 0;
width: 24px;
height: 24px;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
cursor: pointer;
}
.veil {
background-color: rgba(0, 0, 0, 0.5);
}
.veil, #veil-middlebox, #veil-transparentbox {
-moz-transition: 0.1s;
-moz-transition-timing-function: linear;
}
#veil-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#veil {
width: 100%;
height: 100%;
display: -moz-box;
-moz-box-orient: vertical;
}
#veil-topbox, #veil-bottombox {
width: 100%;
}
#veil-bottombox {
-moz-box-flex: 1;
}
#veil-middlebox {
display: -moz-box;
-moz-box-orient: horizontal;
}
#veil-leftbox, #veil-rightbox {
height: 100%;
}
#veil-rightbox {
-moz-box-flex: 1;
}
#veil {
vertical-align: top;
}

View File

@ -19,7 +19,6 @@ browser.jar:
skin/classic/browser/fullscreen-video.css
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
* skin/classic/browser/highlighter.css
skin/classic/browser/Info.png (Info.png)
skin/classic/browser/identity.png (identity.png)
skin/classic/browser/keyhole-forward-mask.svg
@ -134,7 +133,6 @@ browser.jar:
skin/classic/aero/browser/fullscreen-video.css
skin/classic/aero/browser/Geolocation-16.png
skin/classic/aero/browser/Geolocation-64.png
* skin/classic/aero/browser/highlighter.css
skin/classic/aero/browser/Info.png (Info-aero.png)
skin/classic/aero/browser/identity.png (identity-aero.png)
skin/classic/aero/browser/keyhole-forward-mask.svg

View File

@ -67,7 +67,7 @@ def find_version(e):
return encode_ver(last_version)
if __name__ == '__main__':
cxx_env = os.environ.get('CXX', 'c++')
cxx_env = os.environ['CXX']
print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env)
host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env)

View File

@ -112,6 +112,7 @@ MOZ_JPROF = @MOZ_JPROF@
MOZ_SHARK = @MOZ_SHARK@
MOZ_CALLGRIND = @MOZ_CALLGRIND@
MOZ_VTUNE = @MOZ_VTUNE@
MOZ_ETW = @MOZ_ETW@
MOZ_TRACE_JSCALLS = @MOZ_TRACE_JSCALLS@
MOZ_TRACEVIS = @MOZ_TRACEVIS@
DEHYDRA_PATH = @DEHYDRA_PATH@
@ -343,6 +344,7 @@ AS_DASH_C_FLAG = @AS_DASH_C_FLAG@
LD = @LD@
RC = @RC@
RCFLAGS = @RCFLAGS@
MC = @MC@
WINDRES = @WINDRES@
IMPLIB = @IMPLIB@
FILTER = @FILTER@

View File

@ -2020,6 +2020,7 @@ showbuild:
@echo "MKSHLIB = $(MKSHLIB)"
@echo "MKCSHLIB = $(MKCSHLIB)"
@echo "RC = $(RC)"
@echo "MC = $(MC)"
@echo "CFLAGS = $(CFLAGS)"
@echo "OS_CFLAGS = $(OS_CFLAGS)"
@echo "COMPILE_CFLAGS = $(COMPILE_CFLAGS)"

View File

@ -2255,13 +2255,17 @@ ia64*-hpux*)
MOZ_DEBUG_FLAGS="-g" # We want inlining
;;
esac
;;
if test -z "$MC"; then
MC=mc.exe
fi
;;
*-mingw*)
DSO_CFLAGS=
DSO_PIC_CFLAGS=
DLL_SUFFIX=.dll
RC=rc.exe
MC=mc.exe
# certain versions of cygwin's makedepend barf on the
# #include <string> vs -I./dist/include/string issue so don't use it
SYSTEM_MAKEDEPEND=
@ -2549,6 +2553,7 @@ ia64*-hpux*)
TARGET_MD_ARCH=os2
_PLATFORM_DEFAULT_TOOLKIT="cairo-os2"
RC=rc.exe
MC=mc.exe
RCFLAGS='-n'
MOZ_USER_DIR="Mozilla"
ZIP="$ZIP -X"
@ -7547,6 +7552,26 @@ if test -n "$MOZ_GCTIMER"; then
AC_DEFINE(MOZ_GCTIMER)
fi
dnl ========================================================
dnl ETW - Event Tracing for Windows
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(ETW,
[ --enable-ETW Enable ETW (Event Tracing for Windows) event reporting
(needs Windows Vista+ SDK)],
MOZ_ETW=1,
MOZ_ETW= )
if test -n "$MOZ_ETW"; then
AC_DEFINE(MOZ_ETW)
fi
if test -n "$MOZ_ETW"; then
if test -z "$MOZ_WINSDK_TARGETVER"; then
AC_MSG_ERROR([--enable-ETW is only valid on Windows])
elif test "$MOZ_WINSDK_TARGETVER" -lt "06000000"; then
AC_MSG_ERROR([--enable-ETW requires the Windows Vista SDK or newer])
fi
fi
dnl ========================================================
dnl Zealous JavaScript GC
dnl ========================================================
@ -7698,7 +7723,7 @@ MOZ_ARG_ENABLE_BOOL(stdcxx-compat,
AC_SUBST(STDCXX_COMPAT)
if test -n "$STDCXX_COMPAT"; then
eval $($PYTHON $_topsrcdir/build/autoconf/libstdcxx.py)
eval $(CXX="$CXX" $PYTHON $_topsrcdir/build/autoconf/libstdcxx.py)
AC_SUBST(MOZ_LIBSTDCXX_TARGET_VERSION)
AC_SUBST(MOZ_LIBSTDCXX_HOST_VERSION)
fi
@ -8851,6 +8876,7 @@ AC_SUBST(AS_DASH_C_FLAG)
AC_SUBST(LD)
AC_SUBST(RC)
AC_SUBST(RCFLAGS)
AC_SUBST(MC)
AC_SUBST(WINDRES)
AC_SUBST(IMPLIB)
AC_SUBST(FILTER)
@ -8883,6 +8909,7 @@ AC_SUBST(MOZ_JPROF)
AC_SUBST(MOZ_SHARK)
AC_SUBST(MOZ_CALLGRIND)
AC_SUBST(MOZ_VTUNE)
AC_SUBST(MOZ_ETW)
AC_SUBST(MOZ_PROFILING)
AC_SUBST(MOZ_QUANTIFY)
AC_SUBST(LIBICONV)

View File

@ -42,6 +42,7 @@
#include "nsIContent.h"
#include "nsEventStates.h"
#include "nsDOMMemoryReporter.h"
class nsEventStateManager;
class nsGlobalWindow;
@ -97,6 +98,8 @@ public:
{}
#endif // MOZILLA_INTERNAL_API
NS_DECL_AND_IMPL_DOM_MEMORY_REPORTER_SIZEOF(Element, nsIContent)
/**
* Method to get the full state of this element. See nsEventStates.h for
* the possible bits that could be set here.

View File

@ -54,53 +54,111 @@
#include "prmem.h"
#include "nsAutoPtr.h"
#ifndef PR_UINT64_MAX
#define PR_UINT64_MAX (~(PRUint64)(0))
#endif
class nsIFile;
class nsIInputStream;
class nsIClassInfo;
class nsIBlobBuilder;
nsresult NS_NewBlobBuilder(nsISupports* *aSupports);
void ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd);
class nsDOMFile : public nsIDOMFile,
public nsIXHRSendable,
public nsIJSNativeInitializer
class nsDOMFileBase : public nsIDOMFile,
public nsIXHRSendable
{
public:
nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
PRUint64 aLength)
: mIsFile(true), mContentType(aContentType), mName(aName),
mStart(0), mLength(aLength)
{
// Ensure non-null mContentType by default
mContentType.SetIsVoid(PR_FALSE);
}
nsDOMFileBase(const nsAString& aContentType, PRUint64 aLength)
: mIsFile(false), mContentType(aContentType),
mStart(0), mLength(aLength)
{
// Ensure non-null mContentType by default
mContentType.SetIsVoid(PR_FALSE);
}
nsDOMFileBase(const nsAString& aContentType,
PRUint64 aStart, PRUint64 aLength)
: mIsFile(false), mContentType(aContentType),
mStart(aStart), mLength(aLength)
{
NS_ASSERTION(aLength != PR_UINT64_MAX,
"Must know length when creating slice");
// Ensure non-null mContentType by default
mContentType.SetIsVoid(PR_FALSE);
}
virtual ~nsDOMFileBase() {}
virtual already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType) = 0;
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMBLOB
NS_DECL_NSIDOMFILE
NS_DECL_NSIXHRSENDABLE
nsDOMFile(nsIFile *aFile, const nsAString& aContentType,
nsISupports *aCacheToken = nsnull)
: mFile(aFile),
mCacheToken(aCacheToken),
mContentType(aContentType),
mIsFullFile(true)
{}
nsDOMFile(nsIFile *aFile)
: mFile(aFile),
mIsFullFile(true)
{}
nsDOMFile(const nsDOMFile* aOther, PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType)
: mFile(aOther->mFile),
mCacheToken(aOther->mCacheToken),
mStart(aOther->mIsFullFile ? aStart :
(aOther->mStart + aStart)),
mLength(aLength),
mContentType(aContentType),
mIsFullFile(false)
protected:
bool IsSizeUnknown()
{
NS_ASSERTION(mFile, "must have file");
// Ensure non-null mContentType
mContentType.SetIsVoid(PR_FALSE);
return mLength == PR_UINT64_MAX;
}
virtual ~nsDOMFile() {}
bool mIsFile;
nsString mContentType;
nsString mName;
PRUint64 mStart;
PRUint64 mLength;
};
class nsDOMFileFile : public nsDOMFileBase,
public nsIJSNativeInitializer
{
public:
// Create as a file
nsDOMFileFile(nsIFile *aFile)
: nsDOMFileBase(EmptyString(), EmptyString(), PR_UINT64_MAX),
mFile(aFile), mWholeFile(true)
{
NS_ASSERTION(mFile, "must have file");
// Lazily get the content type and size
mContentType.SetIsVoid(PR_TRUE);
mFile->GetLeafName(mName);
}
// Create as a blob
nsDOMFileFile(nsIFile *aFile, const nsAString& aContentType,
nsISupports *aCacheToken = nsnull)
: nsDOMFileBase(aContentType, PR_UINT64_MAX),
mFile(aFile), mWholeFile(true),
mCacheToken(aCacheToken)
{
NS_ASSERTION(mFile, "must have file");
}
// Create as a file to be later initialized
nsDOMFileFile()
: nsDOMFileBase(EmptyString(), EmptyString(), PR_UINT64_MAX),
mWholeFile(true)
{
// Lazily get the content type and size
mContentType.SetIsVoid(PR_TRUE);
mName.SetIsVoid(PR_TRUE);
}
NS_DECL_ISUPPORTS_INHERITED
// nsIJSNativeInitializer
NS_IMETHOD Initialize(nsISupports* aOwner,
@ -109,62 +167,74 @@ public:
PRUint32 aArgc,
jsval* aArgv);
// Overrides
NS_IMETHOD GetSize(PRUint64* aSize);
NS_IMETHOD GetType(nsAString& aType);
NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath);
NS_IMETHOD GetInternalStream(nsIInputStream**);
// DOMClassInfo constructor (for File("foo"))
static nsresult
NewFile(nsISupports* *aNewObject);
protected:
// Create slice
nsDOMFileFile(const nsDOMFileFile* aOther, PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType)
: nsDOMFileBase(aContentType, aOther->mStart + aStart, aLength),
mFile(aOther->mFile), mWholeFile(false),
mCacheToken(aOther->mCacheToken)
{
NS_ASSERTION(mFile, "must have file");
}
virtual already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType);
nsCOMPtr<nsIFile> mFile;
bool mWholeFile;
nsCOMPtr<nsISupports> mCacheToken;
// start and length in
PRUint64 mStart;
PRUint64 mLength;
nsString mContentType;
bool mIsFullFile;
};
class nsDOMMemoryFile : public nsDOMFile
class nsDOMMemoryFile : public nsDOMFileBase
{
public:
// Create as file
nsDOMMemoryFile(void *aMemoryBuffer,
PRUint64 aLength,
const nsAString& aName,
const nsAString& aContentType)
: nsDOMFile(nsnull, aContentType),
mDataOwner(new DataOwner(aMemoryBuffer)),
mName(aName)
: nsDOMFileBase(aName, aContentType, aLength),
mDataOwner(new DataOwner(aMemoryBuffer))
{
mStart = 0;
mLength = aLength;
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
}
// Create as blob
nsDOMMemoryFile(void *aMemoryBuffer,
PRUint64 aLength,
const nsAString& aContentType)
: nsDOMFileBase(aContentType, aLength),
mDataOwner(new DataOwner(aMemoryBuffer))
{
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
}
NS_IMETHOD GetInternalStream(nsIInputStream**);
protected:
// Create slice
nsDOMMemoryFile(const nsDOMMemoryFile* aOther, PRUint64 aStart,
PRUint64 aLength, const nsAString& aContentType)
: nsDOMFile(nsnull, aContentType),
: nsDOMFileBase(aContentType, aOther->mStart + aStart, aLength),
mDataOwner(aOther->mDataOwner)
{
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
mIsFullFile = false;
mStart = aOther->mStart + aStart;
mLength = aLength;
// Ensure non-null mContentType
mContentType.SetIsVoid(PR_FALSE);
}
virtual already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType);
NS_IMETHOD GetName(nsAString&);
NS_IMETHOD GetSize(PRUint64*);
NS_IMETHOD GetInternalStream(nsIInputStream**);
NS_IMETHOD GetMozFullPathInternal(nsAString&);
NS_IMETHOD MozSlice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType, PRUint8 optional_argc,
nsIDOMBlob **aBlob);
protected:
friend class DataOwnerAdapter; // Needs to see DataOwner
class DataOwner {
public:
@ -181,8 +251,6 @@ protected:
// Used when backed by a memory store
nsRefPtr<DataOwner> mDataOwner;
nsString mName;
};
class nsDOMFileList : public nsIDOMFileList

View File

@ -43,6 +43,7 @@
#include "nsChangeHint.h"
#include "nsINode.h"
#include "nsIDocument.h" // for IsInHTMLDocument
#include "nsDOMMemoryReporter.h"
// Forward declarations
class nsIAtom;
@ -76,8 +77,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x860ee35b, 0xe505, 0x438f, \
{ 0xa7, 0x7b, 0x65, 0xb9, 0xf5, 0x0b, 0xe5, 0x29 } }
{ 0x4aad2c06, 0xd6c3, 0x4f44, \
{ 0x94, 0xf9, 0xd5, 0xac, 0xe5, 0x04, 0x67, 0xec } }
/**
* A node of content in a document's content model. This interface
@ -100,6 +101,8 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_IID)
NS_DECL_AND_IMPL_DOM_MEMORY_REPORTER_SIZEOF(nsIContent, nsINode);
/**
* Bind this content node to a tree. If this method throws, the caller must
* call UnbindFromTree() on the node. In the typical case of a node being
@ -946,10 +949,6 @@ public:
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
PRInt64 SizeOf() const {
return sizeof(*this);
}
protected:
/**
* Hook for implementing GetID. This is guaranteed to only be

View File

@ -47,7 +47,7 @@ interface nsIURI;
interface nsIPrincipal;
interface nsIDOMBlob;
[scriptable, uuid(d5237f31-443a-460b-9e42-449a135346f0)]
[scriptable, builtinclass, uuid(d5237f31-443a-460b-9e42-449a135346f0)]
interface nsIDOMBlob : nsISupports
{
readonly attribute unsigned long long size;
@ -58,12 +58,12 @@ interface nsIDOMBlob : nsISupports
// moz-filedata: protocol handler
[noscript] DOMString getInternalUrl(in nsIPrincipal principal);
[optional_argc] nsIDOMBlob mozSlice(in long long start,
[optional_argc] nsIDOMBlob mozSlice([optional] in long long start,
[optional] in long long end,
[optional] in DOMString contentType);
};
[scriptable, uuid(b096ef67-7b77-47f8-8e70-5d8ee36416bf)]
[scriptable, builtinclass, uuid(b096ef67-7b77-47f8-8e70-5d8ee36416bf)]
interface nsIDOMFile : nsIDOMBlob
{
readonly attribute DOMString name;
@ -73,9 +73,10 @@ interface nsIDOMFile : nsIDOMBlob
[noscript] readonly attribute DOMString mozFullPathInternal;
};
[scriptable, uuid(c4a77171-039b-4f84-97f9-820fb51626af)]
[scriptable, builtinclass, uuid(006d2cde-ec18-41d4-acc3-43682dd418e2)]
interface nsIDOMMozBlobBuilder : nsISupports
{
nsIDOMBlob getBlob([optional] in DOMString contentType);
nsIDOMFile getFile(in DOMString name, [optional] in DOMString contentType);
[implicit_jscontext] void append(in jsval data);
};

View File

@ -280,8 +280,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x4776aa9a, 0xa886, 0x40c9, \
{ 0xae, 0x4c, 0x4d, 0x92, 0xe2, 0xf0, 0xd9, 0x61 } }
{ 0xc7abbb40, 0x2571, 0x4d12, \
{ 0x8f, 0x89, 0x0d, 0x4f, 0x55, 0xc0, 0x92, 0xf6 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -294,6 +294,10 @@ class nsINode : public nsIDOMEventTarget,
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
virtual PRInt64 SizeOf() const {
return sizeof(*this);
}
friend class nsNodeUtils;
friend class nsNodeWeakReference;
friend class nsNodeSupportsWeakRefTearoff;

View File

@ -847,3 +847,21 @@ nsAttrAndChildArray::SetChildAtPos(void** aPos, nsIContent* aChild,
next->mPreviousSibling = aChild;
}
}
PRInt64
nsAttrAndChildArray::SizeOf() const
{
PRInt64 size = sizeof(*this);
if (mImpl) {
// Don't add the size taken by *mMappedAttrs because it's shared.
// mBuffer cointains InternalAttr and nsIContent* (even if it's void**)
// so, we just have to compute the size of *mBuffer given that this object
// doesn't own the children list.
size += mImpl->mBufferSize * sizeof(*(mImpl->mBuffer)) + NS_IMPL_EXTRA_SIZE;
}
return size;
}

View File

@ -131,6 +131,8 @@ public:
!AttrSlotIsTaken(ATTRCHILD_ARRAY_MAX_ATTR_COUNT - 1);
}
PRInt64 SizeOf() const;
private:
nsAttrAndChildArray(const nsAttrAndChildArray& aOther); // Not to be implemented
nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther); // Not to be implemented

View File

@ -52,40 +52,40 @@
using namespace mozilla;
class nsDOMMultipartBlob : public nsDOMFile
class nsDOMMultipartFile : public nsDOMFileBase
{
public:
nsDOMMultipartBlob(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
// Create as a file
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aName,
const nsAString& aContentType)
: nsDOMFile(nsnull, aContentType),
: nsDOMFileBase(aName, aContentType, PR_UINT64_MAX),
mBlobs(aBlobs)
{
mIsFullFile = false;
mStart = 0;
mLength = 0;
}
// Create as a blob
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
const nsAString& aContentType)
: nsDOMFileBase(aContentType, PR_UINT64_MAX),
mBlobs(aBlobs)
{
}
already_AddRefed<nsIDOMBlob>
CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType);
NS_IMETHOD GetSize(PRUint64*);
NS_IMETHOD GetInternalStream(nsIInputStream**);
NS_IMETHOD MozSlice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType, PRUint8 optional_argc,
nsIDOMBlob **aBlob);
protected:
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
};
NS_IMETHODIMP
nsDOMMultipartBlob::GetSize(PRUint64* aLength)
nsDOMMultipartFile::GetSize(PRUint64* aLength)
{
nsresult rv;
*aLength = 0;
if (mLength) {
*aLength = mLength;
return NS_OK;
}
if (mLength == PR_UINT64_MAX) {
CheckedUint64 length = 0;
PRUint32 i;
@ -94,22 +94,23 @@ nsDOMMultipartBlob::GetSize(PRUint64* aLength)
nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
PRUint64 l = 0;
rv = blob->GetSize(&l);
nsresult rv = blob->GetSize(&l);
NS_ENSURE_SUCCESS(rv, rv);
length += l;
}
if (!length.valid())
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(length.valid(), NS_ERROR_FAILURE);
mLength = length.value();
}
*aLength = mLength;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMultipartBlob::GetInternalStream(nsIInputStream** aStream)
nsDOMMultipartFile::GetInternalStream(nsIInputStream** aStream)
{
nsresult rv;
*aStream = nsnull;
@ -133,57 +134,37 @@ nsDOMMultipartBlob::GetInternalStream(nsIInputStream** aStream)
return CallQueryInterface(stream, aStream);
}
NS_IMETHODIMP
nsDOMMultipartBlob::MozSlice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType,
PRUint8 optional_argc,
nsIDOMBlob **aBlob)
already_AddRefed<nsIDOMBlob>
nsDOMMultipartFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType)
{
nsresult rv;
*aBlob = nsnull;
// Truncate aStart and aEnd so that we stay within this file.
PRUint64 thisLength;
rv = GetSize(&thisLength);
NS_ENSURE_SUCCESS(rv, rv);
if (!optional_argc) {
aEnd = (PRInt64)thisLength;
}
// Modifies aStart and aEnd.
ParseSize((PRInt64)thisLength, aStart, aEnd);
// If we clamped to nothing we create an empty blob
nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
PRUint64 length = aEnd - aStart;
PRUint64 length = aLength;
PRUint64 skipStart = aStart;
NS_ABORT_IF_FALSE(PRUint64(aStart) + length <= thisLength, "Er, what?");
// Prune the list of blobs if we can
PRUint32 i;
for (i = 0; length && skipStart && i < mBlobs.Length(); i++) {
nsIDOMBlob* blob = mBlobs[i].get();
PRUint64 l;
rv = blob->GetSize(&l);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = blob->GetSize(&l);
NS_ENSURE_SUCCESS(rv, nsnull);
if (skipStart < l) {
PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length);
nsCOMPtr<nsIDOMBlob> firstBlob;
rv = mBlobs.ElementAt(i)->MozSlice(skipStart, skipStart + upperBound,
aContentType, 2,
rv = blob->MozSlice(skipStart, skipStart + upperBound,
aContentType, 3,
getter_AddRefs(firstBlob));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, nsnull);
// Avoid wrapping a single blob inside an nsDOMMultipartBlob
// Avoid wrapping a single blob inside an nsDOMMultipartFile
if (length == upperBound) {
firstBlob.forget(aBlob);
return NS_OK;
return firstBlob.forget();
}
blobs.AppendElement(firstBlob);
@ -199,14 +180,14 @@ nsDOMMultipartBlob::MozSlice(PRInt64 aStart, PRInt64 aEnd,
nsIDOMBlob* blob = mBlobs[i].get();
PRUint64 l;
rv = blob->GetSize(&l);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = blob->GetSize(&l);
NS_ENSURE_SUCCESS(rv, nsnull);
if (length < l) {
nsCOMPtr<nsIDOMBlob> lastBlob;
rv = mBlobs.ElementAt(i)->MozSlice(0, length, aContentType, 2,
rv = blob->MozSlice(0, length, aContentType, 3,
getter_AddRefs(lastBlob));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, nsnull);
blobs.AppendElement(lastBlob);
} else {
@ -216,9 +197,8 @@ nsDOMMultipartBlob::MozSlice(PRInt64 aStart, PRInt64 aEnd,
}
// we can create our blob now
nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(blobs, aContentType);
blob.forget(aBlob);
return NS_OK;
nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(blobs, aContentType);
return blob.forget();
}
class nsDOMBlobBuilder : public nsIDOMMozBlobBuilder
@ -346,7 +326,7 @@ nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
Flush();
nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(mBlobs,
nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(mBlobs,
aContentType);
blob.forget(aBlob);
@ -359,6 +339,30 @@ nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
return NS_OK;
}
/* nsIDOMBlob getFile (in DOMString name, [optional] in DOMString contentType); */
NS_IMETHODIMP
nsDOMBlobBuilder::GetFile(const nsAString& aName,
const nsAString& aContentType,
nsIDOMFile** aFile)
{
NS_ENSURE_ARG(aFile);
Flush();
nsCOMPtr<nsIDOMFile> file = new nsDOMMultipartFile(mBlobs,
aName,
aContentType);
file.forget(aFile);
// NB: This is a willful violation of the spec. The spec says that
// the existing contents of the BlobBuilder should be included
// in the next blob produced. This seems silly and has been raised
// on the WHATWG listserv.
mBlobs.Clear();
return NS_OK;
}
/* [implicit_jscontext] void append (in jsval data); */
NS_IMETHODIMP
nsDOMBlobBuilder::Append(const jsval& aData, JSContext* aCx)

View File

@ -132,57 +132,36 @@ nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
return NS_OK;
}
// nsDOMFile implementation
////////////////////////////////////////////////////////////////////////////
// nsDOMFileBase implementation
DOMCI_DATA(File, nsDOMFile)
DOMCI_DATA(Blob, nsDOMFile)
DOMCI_DATA(File, nsDOMFileBase)
DOMCI_DATA(Blob, nsDOMFileBase)
NS_INTERFACE_MAP_BEGIN(nsDOMFile)
NS_INTERFACE_MAP_BEGIN(nsDOMFileBase)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFullFile)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFullFile)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFullFile)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMFile)
NS_IMPL_RELEASE(nsDOMFile)
NS_IMPL_ADDREF(nsDOMFileBase)
NS_IMPL_RELEASE(nsDOMFileBase)
static nsresult
DOMFileResult(nsresult rv)
NS_IMETHODIMP
nsDOMFileBase::GetName(nsAString &aFileName)
{
if (rv == NS_ERROR_FILE_NOT_FOUND) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
if (NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_FILES) {
return NS_ERROR_DOM_FILE_NOT_READABLE_ERR;
}
return rv;
}
/* static */ nsresult
nsDOMFile::NewFile(nsISupports* *aNewObject)
{
nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMFile(nsnull));
file.forget(aNewObject);
NS_ASSERTION(mIsFile, "Should only be called on files");
aFileName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::GetName(nsAString &aFileName)
nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
{
NS_ASSERTION(mIsFullFile, "Should only be called on files");
return mFile->GetLeafName(aFileName);
}
NS_IMETHODIMP
nsDOMFile::GetMozFullPath(nsAString &aFileName)
{
NS_ASSERTION(mIsFullFile, "Should only be called on files");
NS_ASSERTION(mIsFile, "Should only be called on files");
if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
return GetMozFullPathInternal(aFileName);
}
@ -191,60 +170,30 @@ nsDOMFile::GetMozFullPath(nsAString &aFileName)
}
NS_IMETHODIMP
nsDOMFile::GetMozFullPathInternal(nsAString &aFilename)
nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
{
NS_ASSERTION(mIsFullFile, "Should only be called on files");
return mFile->GetPath(aFilename);
}
NS_IMETHODIMP
nsDOMFile::GetSize(PRUint64 *aFileSize)
{
if (mIsFullFile) {
PRInt64 fileSize;
nsresult rv = mFile->GetFileSize(&fileSize);
NS_ENSURE_SUCCESS(rv, rv);
if (fileSize < 0) {
return NS_ERROR_FAILURE;
}
*aFileSize = fileSize;
}
else {
*aFileSize = mLength;
}
NS_ASSERTION(mIsFile, "Should only be called on files");
aFileName.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::GetType(nsAString &aType)
nsDOMFileBase::GetSize(PRUint64 *aSize)
{
if (mContentType.IsEmpty() && mFile && mIsFullFile) {
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString mimeType;
rv = mimeService->GetTypeFromFile(mFile, mimeType);
if (NS_FAILED(rv)) {
aType.Truncate();
*aSize = mLength;
return NS_OK;
}
AppendUTF8toUTF16(mimeType, mContentType);
}
}
NS_IMETHODIMP
nsDOMFileBase::GetType(nsAString &aType)
{
aType = mContentType;
return NS_OK;
}
// Makes sure that aStart and aEnd is less then or equal to aSize and greater
// than 0
void
static void
ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
{
CheckedInt64 newStartOffset = aStart;
@ -280,7 +229,7 @@ ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
}
NS_IMETHODIMP
nsDOMFile::MozSlice(PRInt64 aStart, PRInt64 aEnd,
nsDOMFileBase::MozSlice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType, PRUint8 optional_argc,
nsIDOMBlob **aBlob)
{
@ -291,34 +240,30 @@ nsDOMFile::MozSlice(PRInt64 aStart, PRInt64 aEnd,
nsresult rv = GetSize(&thisLength);
NS_ENSURE_SUCCESS(rv, rv);
if (!optional_argc) {
if (optional_argc < 2) {
aEnd = (PRInt64)thisLength;
}
ParseSize((PRInt64)thisLength, aStart, aEnd);
// Create the new file
NS_ADDREF(*aBlob = new nsDOMFile(this, aStart, aEnd - aStart, aContentType));
*aBlob = CreateSlice((PRUint64)aStart, (PRUint64)(aEnd - aStart),
aContentType).get();
return NS_OK;
return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
}
const PRUint32 sFileStreamFlags =
nsIFileInputStream::CLOSE_ON_EOF |
nsIFileInputStream::REOPEN_ON_REWIND |
nsIFileInputStream::DEFER_OPEN;
NS_IMETHODIMP
nsDOMFile::GetInternalStream(nsIInputStream **aStream)
nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
{
return mIsFullFile ?
NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
-1, -1, sFileStreamFlags);
// Must be overridden
NS_NOTREACHED("Must override GetInternalStream");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMFile::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
{
NS_ENSURE_STATE(aPrincipal);
@ -346,7 +291,7 @@ nsDOMFile::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
}
NS_IMETHODIMP
nsDOMFile::GetSendInfo(nsIInputStream** aBody,
nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
nsACString& aContentType,
nsACString& aCharset)
{
@ -368,8 +313,99 @@ nsDOMFile::GetSendInfo(nsIInputStream** aBody,
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// nsDOMFileFile implementation
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMFileFile, nsDOMFileBase,
nsIJSNativeInitializer)
already_AddRefed<nsIDOMBlob>
nsDOMFileFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType)
{
nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
return t.forget();
}
/* static */ nsresult
nsDOMFileFile::NewFile(nsISupports* *aNewObject)
{
nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMFileFile());
file.forget(aNewObject);
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::Initialize(nsISupports* aOwner,
nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
{
NS_ASSERTION(mIsFile, "Should only be called on files");
return mFile->GetPath(aFilename);
}
NS_IMETHODIMP
nsDOMFileFile::GetSize(PRUint64 *aFileSize)
{
if (IsSizeUnknown()) {
NS_ASSERTION(mWholeFile,
"Should only use lazy size when using the whole file");
PRInt64 fileSize;
nsresult rv = mFile->GetFileSize(&fileSize);
NS_ENSURE_SUCCESS(rv, rv);
if (fileSize < 0) {
return NS_ERROR_FAILURE;
}
mLength = fileSize;
}
*aFileSize = mLength;
return NS_OK;
}
NS_IMETHODIMP
nsDOMFileFile::GetType(nsAString &aType)
{
if (mContentType.IsVoid()) {
NS_ASSERTION(mWholeFile,
"Should only use lazy ContentType when using the whole file");
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString mimeType;
rv = mimeService->GetTypeFromFile(mFile, mimeType);
if (NS_FAILED(rv)) {
mimeType.Truncate();
}
AppendUTF8toUTF16(mimeType, mContentType);
mContentType.SetIsVoid(PR_FALSE);
}
aType = mContentType;
return NS_OK;
}
const PRUint32 sFileStreamFlags =
nsIFileInputStream::CLOSE_ON_EOF |
nsIFileInputStream::REOPEN_ON_REWIND |
nsIFileInputStream::DEFER_OPEN;
NS_IMETHODIMP
nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
{
return mWholeFile ?
NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
-1, -1, sFileStreamFlags);
}
NS_IMETHODIMP
nsDOMFileFile::Initialize(nsISupports* aOwner,
JSContext* aCx,
JSObject* aObj,
PRUint32 aArgc,
@ -430,44 +466,21 @@ nsDOMFile::Initialize(nsISupports* aOwner,
NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
mFile = file;
file->GetLeafName(mName);
return NS_OK;
}
// nsDOMMemoryFile Implementation
NS_IMETHODIMP
nsDOMMemoryFile::GetName(nsAString &aFileName)
////////////////////////////////////////////////////////////////////////////
// nsDOMMemoryFile implementation
already_AddRefed<nsIDOMBlob>
nsDOMMemoryFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
const nsAString& aContentType)
{
NS_ASSERTION(mIsFullFile, "Should only be called on files");
aFileName = mName;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryFile::GetSize(PRUint64 *aFileSize)
{
*aFileSize = mLength;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryFile::MozSlice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType, PRUint8 optional_argc,
nsIDOMBlob **aBlob)
{
*aBlob = nsnull;
if (!optional_argc) {
aEnd = (PRInt64)mLength;
}
// Truncate aLength and aStart so that we stay within this file.
ParseSize((PRInt64)mLength, aStart, aEnd);
// Create the new file
NS_ADDREF(*aBlob = new nsDOMMemoryFile(this, aStart, aEnd - aStart,
aContentType));
return NS_OK;
nsCOMPtr<nsIDOMBlob> t =
new nsDOMMemoryFile(this, aStart, aLength, aContentType);
return t.forget();
}
NS_IMETHODIMP
@ -479,14 +492,7 @@ nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
}
NS_IMETHODIMP
nsDOMMemoryFile::GetMozFullPathInternal(nsAString &aFilename)
{
NS_ASSERTION(mIsFullFile, "Should only be called on files");
aFilename.Truncate();
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// nsDOMFileList implementation
DOMCI_DATA(FileList, nsDOMFileList)
@ -516,6 +522,7 @@ nsDOMFileList::Item(PRUint32 aIndex, nsIDOMFile **aFile)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// nsDOMFileError implementation
DOMCI_DATA(FileError, nsDOMFileError)
@ -536,6 +543,9 @@ nsDOMFileError::GetCode(PRUint16* aCode)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// nsDOMFileInternalUrlHolder implementation
nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
nsIPrincipal* aPrincipal
MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {

View File

@ -146,6 +146,7 @@
#include "prprf.h"
#include "nsSVGFeatures.h"
#include "nsDOMMemoryReporter.h"
using namespace mozilla::dom;
namespace css = mozilla::css;
@ -5372,3 +5373,15 @@ nsNSElementTearoff::MozMatchesSelector(const nsAString& aSelector, PRBool* aRetu
return rv;
}
PRInt64
nsGenericElement::SizeOf() const
{
PRInt64 size = MemoryReporter::GetBasicSize<nsGenericElement, Element>(this);
size -= sizeof(mAttrsAndChildren);
size += mAttrsAndChildren.SizeOf();
return size;
}

View File

@ -240,6 +240,8 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
/**
* Called during QueryInterface to give the binding manager a chance to
* get an interface for this element.

View File

@ -1351,6 +1351,18 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
rv = ParseURL(PromiseFlatString(aURL));
NS_ENSURE_SUCCESS(rv, rv);
// Don't allow https:// to open ws://
nsCOMPtr<nsIURI> originURI;
PRBool originHTTPS;
if (!mSecure &&
!Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
PR_FALSE) &&
NS_SUCCEEDED(NS_NewURI(getter_AddRefs(originURI), mUTF16Origin)) &&
NS_SUCCEEDED(originURI->SchemeIs("https", &originHTTPS)) &&
originHTTPS) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// sets the protocol
if (!aProtocol.IsEmpty()) {
rv = SetProtocol(PromiseFlatString(aProtocol));

View File

@ -1600,13 +1600,6 @@ void nsXMLHttpRequest::CreateResponseBlob(nsIRequest *request)
nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(request));
if (cc) {
cc->GetCacheFile(getter_AddRefs(file));
if (!file) {
// cacheAsFile returns false if caching is inhibited
PRBool cacheAsFile = PR_FALSE;
if (NS_SUCCEEDED(cc->GetCacheAsFile(&cacheAsFile)) && cacheAsFile) {
}
}
} else {
nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(request);
if (fc) {
@ -1621,20 +1614,8 @@ void nsXMLHttpRequest::CreateResponseBlob(nsIRequest *request)
cc->GetCacheToken(getter_AddRefs(cacheToken));
}
NS_ConvertASCIItoUTF16 wideContentType(contentType);
nsCOMPtr<nsIDOMBlob> blob =
new nsDOMFile(file, wideContentType, cacheToken);
// XXXkhuey this is a complete hack ... but we need to get 6 out the door
// The response blob here should not be a File object, it should only
// be a Blob. Unfortunately, because nsDOMFile has grown through
// accretion over the years and is in dangerous need of a refactoring,
// slicing it is the easiest way to get there ...
PRUint64 size = 0;
blob->GetSize(&size);
blob->MozSlice(0, size, wideContentType, 2, getter_AddRefs(mResponseBlob));
mResponseBlob =
new nsDOMFileFile(file, NS_ConvertASCIItoUTF16(contentType), cacheToken);
mResponseBody.Truncate();
mResponseBodyUnicode.SetIsVoid(PR_TRUE);
}
@ -1906,19 +1887,9 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
if (blobData) {
memcpy(blobData, mResponseBody.BeginReading(), blobLen);
NS_ConvertASCIItoUTF16 wideContentType(contentType);
nsCOMPtr<nsIDOMBlob> blob =
new nsDOMMemoryFile(blobData, blobLen, EmptyString(),
wideContentType);
// XXXkhuey this is a complete hack ... but we need to get 6 out the door
// The response blob here should not be a File object, it should only
// be a Blob. Unfortunately, because nsDOMFile has grown through
// accretion over the years and is in dangerous need of a refactoring,
// slicing it is the easiest way to get there ...
blob->MozSlice(0, blobLen, wideContentType,
2, getter_AddRefs(mResponseBlob));
mResponseBlob =
new nsDOMMemoryFile(blobData, blobLen,
NS_ConvertASCIItoUTF16(contentType));
mResponseBody.Truncate();
}
NS_ASSERTION(mResponseBodyUnicode.IsVoid(),

View File

@ -220,6 +220,7 @@ function testSlice(file, size, type, contents, fileType) {
is(slice.mozSlice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
is(slice.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
// Start, end, expected size
var indexes = [[0, size, size],
[0, 1234, 1234],
[size-500, size, 500],
@ -228,6 +229,7 @@ function testSlice(file, size, type, contents, fileType) {
[0, 0, 0],
[1000, 1000, 0],
[size, size, 0],
[undefined, undefined, size],
[0, undefined, size],
[100, undefined, size-100],
[-100, undefined, 100],
@ -244,7 +246,12 @@ function testSlice(file, size, type, contents, fileType) {
for (var i = 0; i < indexes.length; ++i) {
var sliceContents;
var testName;
if (indexes[i][1] == undefined) {
if (indexes[i][0] == undefined) {
slice = file.mozSlice();
sliceContents = contents.slice();
testName = fileType + " slice()";
}
else if (indexes[i][1] == undefined) {
slice = file.mozSlice(indexes[i][0]);
sliceContents = contents.slice(indexes[i][0]);
testName = fileType + " slice(" + indexes[i][0] + ")";

View File

@ -28,6 +28,7 @@ ok(blobBuilder, "BlobBuilder should exist");
ok(blobBuilder.append, "BlobBuilder should have an append method");
ok(blobBuilder.getBlob, "BlobBuilder should have a getBlob method");
ok(blobBuilder.getFile, "BlobBuilder should have a getFile method");
try {
blobBuilder.append();
@ -38,8 +39,43 @@ ok(true, "an empty argument to append should throw");
blobBuilder.append("squiggle");
let blob1 = blobBuilder.getBlob();
ok(blob1 instanceof Blob, "getBlob should produce Blobs");
ok(!(blob1 instanceof File), "getBlob should not produce Files");
is(blob1.type, "", "getBlob with no argument should return Blob with empty type");
is(blob1.size, 8, "getBlob should return Blob with correct size");
blobBuilder.append("ohai");
let blob2 = blobBuilder.getBlob();
let blob2 = blobBuilder.getFile("thefilename");
ok(blob2 instanceof Blob, "getFile should produce Blobs");
ok(blob2 instanceof File, "getFile should produce Files");
is(blob2.name, "thefilename", "getFile should produces Files with correct name");
is(blob2.type, "", "getFile with no second argument should return File with empty type");
is(blob2.size, 4, "getFile should return Blob with correct size");
blobBuilder.append("steak");
let blob3 = blobBuilder.getBlob("content/type");
ok(blob3 instanceof Blob, "getBlob should produce Blobs");
ok(!(blob3 instanceof File), "getBlob should not produce Files");
is(blob3.type, "content/type", "getBlob with no argument should return Blob with empty type");
is(blob3.size, 5, "getBlob should return Blob with correct size");
blobBuilder.append("apples");
let blob4 = blobBuilder.getFile("the other filename", "text/plain");
ok(blob4 instanceof Blob, "getFile should produce Blobs");
ok(blob4 instanceof File, "getFile should produce Files");
is(blob4.name, "the other filename", "getFile should produces Files with correct name");
is(blob4.type, "text/plain", "getFile with second argument should return File with correct type");
is(blob4.size, 6, "getFile should return Blob with correct size");
blobBuilder.append("boletes");
let blob5 = blobBuilder.getFile("");
ok(blob5 instanceof Blob, "getFile should produce Blobs");
ok(blob5 instanceof File, "getFile should produce Files");
is(blob5.name, "", "getFile with empty name should produces Files with empty name");
is(blob5.type, "", "getFile with no second argument should return File with correct type");
is(blob5.size, 7, "getFile should return Blob with correct size");
testFile(blob5, "boletes", "Test empty-named File from BlobBuilder.getFile");
let aB = new ArrayBuffer(16);
var int8View = new Int8Array(aB);
@ -54,10 +90,10 @@ let testData =
{start: 0, length: 3, contents: "foo"},
{start: 3, length:6, contents: "barbaz"},
{start: 6, length: 3, contents: "baz"},
{start: 6, length: 6, elength: 3, contents: "baz"},
{start: 6, length: 6, contents: "baz"},
{start: 0, length: 9, contents: "foobarbaz"},
{start: 0, length: 11, elength: 9, contents: "foobarbaz"},
{start: 10, length: 5, elength: 0, contents: ""}]],
{start: 0, length: 11, contents: "foobarbaz"},
{start: 10, length: 5, contents: ""}]],
// Test string, Blob, string
[["foo", blob1, "baz"], [{start: 0, length: 3, contents: "foo"},
{start: 3, length: 8, contents: "squiggle"},
@ -69,7 +105,7 @@ let testData =
{start: 10, length: 2, contents: "os"},
{start: 1, length: 3, contents: "qui"},
{start: 12, length: 3, contents: "qui"},
{start: 40, length: 20, elength: 0, contents: ""}]],
{start: 40, length: 20, contents: ""}]],
// Test blobs all the way down
[[blob2, blob1, blob2], [{start: 0, length: 4, contents: "ohai"},
{start: 4, length: 8, contents: "squiggle"},
@ -84,7 +120,7 @@ let testData =
// Test type coercion of a number
[[3, aB, "foo"], [{start: 0, length: 8, contents: "3ABCDEFG"},
{start: 8, length:10, contents: "HIJKLMNOPf"},
{start: 17, length: 4, elength: 3, contents: "foo"},
{start: 17, length: 4, contents: "foo"},
{start: 4, length: 8, contents: "DEFGHIJK"}]]
];
@ -110,17 +146,16 @@ function doTest(data) {
let blob = bb.getBlob();
ok(blob, "Test " + testCounter + " got blob");
ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
//ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
let slice = blob.mozSlice(test.start, test.start + test.length);
ok(slice, "Test " + testCounter + " got slice");
ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob");
//ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");
is(slice.size,"elength" in test ? test.elength : test.length,
ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");
is(slice.size, test.contents.length,
"Test " + testCounter + " slice is correct size");
testFile(slice, test.contents, "Test " + testCounter,
"elength" in test ? test.elength : test.length);
testFile(slice, test.contents, "Test " + testCounter);
}
tests.forEach(runTest);
SpecialPowers.gc();

View File

@ -103,6 +103,7 @@
#include "nsFrameManager.h"
#include "nsFrameLoader.h"
#include "nsBidi.h"
#include "nsBidiPresUtils.h"
#include "Layers.h"
#include "CanvasUtils.h"
@ -1068,6 +1069,8 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
mZero = PR_TRUE;
height = 1;
width = 1;
} else {
mZero = PR_FALSE;
}
gfxASurface::gfxImageFormat format = GetImageFormat();
@ -2736,10 +2739,6 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
nsIDocument* document = presShell->GetDocument();
nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils();
if (!bidiUtils)
return NS_ERROR_FAILURE;
// replace all the whitespace characters with U+0020 SPACE
nsAutoString textToDraw(aRawText);
TextReplaceWhitespaceCharacters(textToDraw);
@ -2785,7 +2784,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
// calls bidi algo twice since it needs the full text width and the
// bounding boxes before rendering anything
rv = bidiUtils->ProcessText(textToDraw.get(),
nsBidi bidiEngine;
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
textToDraw.Length(),
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
presShell->GetPresContext(),
@ -2793,7 +2793,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
nsBidiPresUtils::MODE_MEASURE,
nsnull,
0,
&totalWidthCoord);
&totalWidthCoord,
&bidiEngine);
if (NS_FAILED(rv))
return rv;
@ -2892,7 +2893,7 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
processor.mThebes = ctx;
rv = bidiUtils->ProcessText(textToDraw.get(),
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
textToDraw.Length(),
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
presShell->GetPresContext(),
@ -2900,7 +2901,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
nsBidiPresUtils::MODE_DRAW,
nsnull,
0,
nsnull);
nsnull,
&bidiEngine);
if (NS_FAILED(rv))
return rv;
@ -2929,7 +2931,7 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
ApplyStyle(STYLE_FILL);
}
rv = bidiUtils->ProcessText(textToDraw.get(),
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
textToDraw.Length(),
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
presShell->GetPresContext(),
@ -2937,7 +2939,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
nsBidiPresUtils::MODE_DRAW,
nsnull,
0,
nsnull);
nsnull,
&bidiEngine);
// this needs to be restored before function can return
if (doUseIntermediateSurface) {

View File

@ -100,6 +100,7 @@
#include "nsFrameManager.h"
#include "nsFrameLoader.h"
#include "nsBidi.h"
#include "nsBidiPresUtils.h"
#include "Layers.h"
#include "CanvasUtils.h"
@ -1226,6 +1227,8 @@ nsCanvasRenderingContext2DAzure::SetDimensions(PRInt32 width, PRInt32 height)
mZero = PR_TRUE;
height = 1;
width = 1;
} else {
mZero = PR_FALSE;
}
// Check that the dimensions are sane
@ -3194,11 +3197,6 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
nsIDocument* document = presShell->GetDocument();
nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils();
if (!bidiUtils) {
return NS_ERROR_FAILURE;
}
// replace all the whitespace characters with U+0020 SPACE
nsAutoString textToDraw(aRawText);
TextReplaceWhitespaceCharacters(textToDraw);
@ -3249,7 +3247,8 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
// calls bidi algo twice since it needs the full text width and the
// bounding boxes before rendering anything
rv = bidiUtils->ProcessText(textToDraw.get(),
nsBidi bidiEngine;
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
textToDraw.Length(),
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
presShell->GetPresContext(),
@ -3257,7 +3256,8 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
nsBidiPresUtils::MODE_MEASURE,
nsnull,
0,
&totalWidthCoord);
&totalWidthCoord,
&bidiEngine);
if (NS_FAILED(rv)) {
return rv;
}
@ -3348,7 +3348,7 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
// don't ever need to measure the bounding box twice
processor.mDoMeasureBoundingBox = PR_FALSE;
rv = bidiUtils->ProcessText(textToDraw.get(),
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
textToDraw.Length(),
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
presShell->GetPresContext(),
@ -3356,7 +3356,8 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
nsBidiPresUtils::MODE_DRAW,
nsnull,
0,
nsnull);
nsnull,
&bidiEngine);
mTarget->SetTransform(oldTransform);

View File

@ -21392,6 +21392,27 @@ function test_zero_dimensions_imagedata() {
}
</script>
<p>Canvas test: getImageData_after_zero_canvas</p>
<canvas id="c686" width="100" height="100"></canvas>
<script type="text/javascript">
function test_getImageData_after_zero_canvas() {
var c = document.getElementById("c686");
var ctx = c.getContext("2d");
ctx.fillStyle = "rgba(0, 0, 0, 1.0)";
ctx.fillRect(0, 0, c.width, c.height);
var oldimgdata = ctx.getImageData(0, 0, c.width, c.height);
c.width = c.height = 0;
c.width = c.height = 100;
ctx.fillRect(0, 0, c.width, c.height);
var imgdata = ctx.getImageData(0, 0, c.width, c.height);
var same = false;
ok(imgdata.data.length === oldimgdata.data.length, "not the same length");
for (var i = 0; i < imgdata.data.length; ++i)
same = imgdata.data[i] === oldimgdata.data[i];
ok(same, "changing dimensions broke canvas");
}
</script>
<script>
function asyncTestsDone() {
@ -24661,6 +24682,12 @@ function runTests() {
} catch(e) {
ok(false, "unexpected exception thrown in: test_zero_dimensions_imagedata");
}
try {
test_getImageData_after_zero_canvas();
} catch(e) {
throw e;
ok(false, "unexpected exception thrown in: test_getImageData_after_zero_canvas");
}
try {
// run this test last since it replaces the getContext method
test_type_replace();

View File

@ -255,7 +255,7 @@ nsDOMDataTransfer::GetFiles(nsIDOMFileList** aFileList)
if (!file)
continue;
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(file);
nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
if (!mFiles->Append(domFile))
return NS_ERROR_FAILURE;

View File

@ -2103,17 +2103,6 @@ nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
return SetAttr(kNameSpaceID_None, aAttr, aValue, PR_TRUE);
}
nsresult
nsGenericHTMLElement::GetStringAttrWithDefault(nsIAtom* aAttr,
const char* aDefault,
nsAString& aResult)
{
if (!GetAttr(kNameSpaceID_None, aAttr, aResult)) {
CopyASCIItoUTF16(aDefault, aResult);
}
return NS_OK;
}
nsresult
nsGenericHTMLElement::SetBoolAttr(nsIAtom* aAttr, PRBool aValue)
{

View File

@ -609,19 +609,6 @@ protected:
*/
NS_HIDDEN_(nsresult) SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue);
/**
* Helper method for NS_IMPL_STRING_ATTR_DEFAULT_VALUE macro.
* Gets the value of an attribute, returns specified default value if the
* attribute isn't set. Only works for attributes in null namespace.
*
* @param aAttr name of attribute.
* @param aDefault default-value to return if attribute isn't set.
* @param aResult result value [out]
*/
NS_HIDDEN_(nsresult) GetStringAttrWithDefault(nsIAtom* aAttr,
const char* aDefault,
nsAString& aResult);
/**
* Helper method for NS_IMPL_BOOL_ATTR macro.
* Gets value of boolean attribute. Only works for attributes in null
@ -1084,23 +1071,6 @@ protected:
return SetAttrHelper(nsGkAtoms::_atom, aValue); \
}
/**
* A macro to implement the getter and setter for a given string
* valued content property with a default value.
* The method uses the generic GetAttr and SetAttr methods.
*/
#define NS_IMPL_STRING_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \
NS_IMETHODIMP \
_class::Get##_method(nsAString& aValue) \
{ \
return GetStringAttrWithDefault(nsGkAtoms::_atom, _default, aValue);\
} \
NS_IMETHODIMP \
_class::Set##_method(const nsAString& aValue) \
{ \
return SetAttrHelper(nsGkAtoms::_atom, aValue); \
}
/**
* A macro to implement the getter and setter for a given boolean
* valued content property. The method uses the generic GetAttr and

View File

@ -287,11 +287,13 @@ nsHTMLImageElement::GetWidthHeight()
}
}
NS_ASSERTION(size.width >= 0, "negative width");
NS_ASSERTION(size.height >= 0, "negative height");
return size;
}
NS_IMETHODIMP
nsHTMLImageElement::GetHeight(PRInt32* aHeight)
nsHTMLImageElement::GetHeight(PRUint32* aHeight)
{
*aHeight = GetWidthHeight().height;
@ -299,7 +301,7 @@ nsHTMLImageElement::GetHeight(PRInt32* aHeight)
}
NS_IMETHODIMP
nsHTMLImageElement::SetHeight(PRInt32 aHeight)
nsHTMLImageElement::SetHeight(PRUint32 aHeight)
{
nsAutoString val;
val.AppendInt(aHeight);
@ -309,7 +311,7 @@ nsHTMLImageElement::SetHeight(PRInt32 aHeight)
}
NS_IMETHODIMP
nsHTMLImageElement::GetWidth(PRInt32* aWidth)
nsHTMLImageElement::GetWidth(PRUint32* aWidth)
{
*aWidth = GetWidthHeight().width;
@ -317,7 +319,7 @@ nsHTMLImageElement::GetWidth(PRInt32* aWidth)
}
NS_IMETHODIMP
nsHTMLImageElement::SetWidth(PRInt32 aWidth)
nsHTMLImageElement::SetWidth(PRUint32 aWidth)
{
nsAutoString val;
val.AppendInt(aWidth);
@ -576,7 +578,7 @@ nsHTMLImageElement::Initialize(nsISupports* aOwner, JSContext* aContext,
}
NS_IMETHODIMP
nsHTMLImageElement::GetNaturalHeight(PRInt32* aNaturalHeight)
nsHTMLImageElement::GetNaturalHeight(PRUint32* aNaturalHeight)
{
NS_ENSURE_ARG_POINTER(aNaturalHeight);
@ -592,12 +594,15 @@ nsHTMLImageElement::GetNaturalHeight(PRInt32* aNaturalHeight)
return NS_OK;
}
image->GetHeight(aNaturalHeight);
PRInt32 height;
if (NS_SUCCEEDED(image->GetHeight(&height))) {
*aNaturalHeight = height;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLImageElement::GetNaturalWidth(PRInt32* aNaturalWidth)
nsHTMLImageElement::GetNaturalWidth(PRUint32* aNaturalWidth)
{
NS_ENSURE_ARG_POINTER(aNaturalWidth);
@ -613,7 +618,10 @@ nsHTMLImageElement::GetNaturalWidth(PRInt32* aNaturalWidth)
return NS_OK;
}
image->GetWidth(aNaturalWidth);
PRInt32 width;
if (NS_SUCCEEDED(image->GetWidth(&width))) {
*aNaturalWidth = width;
}
return NS_OK;
}

View File

@ -404,7 +404,7 @@ AsyncClickHandler::Run()
rv = localFile->GetPath(unicodePath);
if (!unicodePath.IsEmpty()) {
nsCOMPtr<nsIDOMFile> domFile =
do_QueryObject(new nsDOMFile(localFile));
do_QueryObject(new nsDOMFileFile(localFile));
newFiles.AppendObject(domFile);
}
if (!prefSaved) {
@ -424,7 +424,7 @@ AsyncClickHandler::Run()
rv = localFile->GetPath(unicodePath);
if (!unicodePath.IsEmpty()) {
nsCOMPtr<nsIDOMFile> domFile=
do_QueryObject(new nsDOMFile(localFile));
do_QueryObject(new nsDOMFileFile(localFile));
newFiles.AppendObject(domFile);
}
// Store the last used directory using the content pref service
@ -1149,7 +1149,7 @@ nsHTMLInputElement::MozSetFileNameArray(const PRUnichar **aFileNames, PRUint32 a
}
if (file) {
nsCOMPtr<nsIDOMFile> domFile = new nsDOMFile(file);
nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(file);
files.AppendObject(domFile);
} else {
continue; // Not much we can do if the file doesn't exist

View File

@ -1987,11 +1987,11 @@ void nsHTMLMediaElement::NetworkError()
void nsHTMLMediaElement::DecodeError()
{
if (mIsLoadingFromSourceChildren) {
if (mDecoder) {
mDecoder->Shutdown();
mDecoder = nsnull;
}
if (mIsLoadingFromSourceChildren) {
mError = nsnull;
if (mSourceLoadCandidate) {
DispatchAsyncSourceError(mSourceLoadCandidate);

View File

@ -222,7 +222,7 @@ nsHTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Abbr, abbr)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Axis, axis)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, BgColor, bgcolor)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, Ch, _char, ".")
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Ch, _char)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, ChOff, charoff)
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, ColSpan, colspan, 1)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Headers, headers)
@ -230,7 +230,7 @@ NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Height, height)
NS_IMPL_BOOL_ATTR(nsHTMLTableCellElement, NoWrap, nowrap)
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, RowSpan, rowspan, 1)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Scope, scope)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, VAlign, valign, "middle")
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, VAlign, valign)
NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Width, width)

View File

@ -111,11 +111,11 @@ NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLTableColElement)
NS_IMPL_ELEMENT_CLONE(nsHTMLTableColElement)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableColElement, Align, align, "left")
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableColElement, Ch, _char, ".")
NS_IMPL_STRING_ATTR(nsHTMLTableColElement, Align, align)
NS_IMPL_STRING_ATTR(nsHTMLTableColElement, Ch, _char)
NS_IMPL_STRING_ATTR(nsHTMLTableColElement, ChOff, charoff)
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableColElement, Span, span, 1)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableColElement, VAlign, valign, "middle")
NS_IMPL_STRING_ATTR(nsHTMLTableColElement, VAlign, valign)
NS_IMPL_STRING_ATTR(nsHTMLTableColElement, Width, width)

View File

@ -965,17 +965,10 @@ nsHTMLTableElement::ParseAttribute(PRInt32 aNamespaceID,
aAttribute == nsGkAtoms::cellpadding) {
return aResult.ParseSpecialIntValue(aValue);
}
if (aAttribute == nsGkAtoms::cols) {
if (aAttribute == nsGkAtoms::cols ||
aAttribute == nsGkAtoms::border) {
return aResult.ParseIntWithBounds(aValue, 0);
}
if (aAttribute == nsGkAtoms::border) {
if (!aResult.ParseIntWithBounds(aValue, 0)) {
// XXX this should really be NavQuirks only to allow non numeric value
aResult.SetTo(1);
}
return PR_TRUE;
}
if (aAttribute == nsGkAtoms::height) {
return aResult.ParseSpecialIntValue(aValue);
}
@ -983,15 +976,13 @@ nsHTMLTableElement::ParseAttribute(PRInt32 aNamespaceID,
if (aResult.ParseSpecialIntValue(aValue)) {
// treat 0 width as auto
nsAttrValue::ValueType type = aResult.Type();
if ((type == nsAttrValue::eInteger &&
return !((type == nsAttrValue::eInteger &&
aResult.GetIntegerValue() == 0) ||
(type == nsAttrValue::ePercent &&
aResult.GetPercentValue() == 0.0f)) {
aResult.GetPercentValue() == 0.0f));
}
return PR_FALSE;
}
}
return PR_TRUE;
}
if (aAttribute == nsGkAtoms::align) {
return ParseTableHAlignValue(aValue, aResult);

View File

@ -359,11 +359,11 @@ nsHTMLTableRowElement::DeleteCell(PRInt32 aValue)
return RemoveChild(cell, getter_AddRefs(retChild));
}
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableRowElement, Align, align, "left")
NS_IMPL_STRING_ATTR(nsHTMLTableRowElement, Align, align)
NS_IMPL_STRING_ATTR(nsHTMLTableRowElement, BgColor, bgcolor)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableRowElement, Ch, _char, ".")
NS_IMPL_STRING_ATTR(nsHTMLTableRowElement, Ch, _char)
NS_IMPL_STRING_ATTR(nsHTMLTableRowElement, ChOff, charoff)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableRowElement, VAlign, valign, "middle")
NS_IMPL_STRING_ATTR(nsHTMLTableRowElement, VAlign, valign)
PRBool

View File

@ -120,9 +120,9 @@ NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLTableSectionElement)
NS_IMPL_ELEMENT_CLONE(nsHTMLTableSectionElement)
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableSectionElement, Align, align, "left")
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableSectionElement, VAlign, valign, "middle")
NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableSectionElement, Ch, _char, ".")
NS_IMPL_STRING_ATTR(nsHTMLTableSectionElement, Align, align)
NS_IMPL_STRING_ATTR(nsHTMLTableSectionElement, VAlign, valign)
NS_IMPL_STRING_ATTR(nsHTMLTableSectionElement, Ch, _char)
NS_IMPL_STRING_ATTR(nsHTMLTableSectionElement, ChOff, charoff)

View File

@ -273,6 +273,7 @@ _TEST_FILES = \
test_bug659596.html \
test_bug659743.xml \
test_bug660663.html \
test_bug586786.html \
test_restore_from_parser_fragment.html \
$(NULL)

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=586786
-->
<head>
<title>Test for Bug 586786</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=586786">Mozilla Bug 586786</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 586786 **/
var elements = ["col", "colgroup", "tbody", "tfoot", "thead", "tr", "td", "th"];
for(var i = 0; i < elements.length; i++)
{
reflectString({
element: document.createElement(elements[i]),
attribute: "align",
otherValues: [ "left", "right", "center", "justify", "char" ]
});
reflectString({
element: document.createElement(elements[i]),
attribute: "vAlign",
otherValues: [ "top", "middle", "bottom", "baseline" ]
});
reflectString({
element: document.createElement(elements[i]),
attribute: {idl: "ch", content: "char"}
});
}
// table.border, table.width
reflectString({
element: document.createElement("table"),
attribute: "border"
});
reflectString({
element: document.createElement("table"),
attribute: "width"
});
</script>
</pre>
</body>
</html>

View File

@ -76,9 +76,11 @@ public:
// Initialize the audio stream. aNumChannels is the number of audio channels
// (1 for mono, 2 for stereo, etc) and aRate is the frequency of the sound
// samples (22050, 44100, etc).
// Unsafe to call with the decoder monitor held.
virtual nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat) = 0;
// Closes the stream. All future use of the stream is an error.
// Unsafe to call with the decoder monitor held.
virtual void Shutdown() = 0;
// Write sound data to the audio hardware. aBuf is an array of samples in
@ -98,6 +100,7 @@ public:
virtual void SetVolume(double aVolume) = 0;
// Block until buffered audio data has been consumed.
// Unsafe to call with the decoder monitor held.
virtual void Drain() = 0;
// Pause audio playback
@ -119,6 +122,7 @@ public:
// Returns the minimum number of samples which must be written before
// you can be sure that something will be played.
// Unsafe to call with the decoder monitor held.
virtual PRInt32 GetMinWriteSamples() = 0;
protected:

View File

@ -46,6 +46,7 @@
#include "nsTArray.h"
#include "VideoUtils.h"
#include "nsBuiltinDecoder.h"
#include "nsBuiltinDecoderStateMachine.h"
using namespace mozilla;
@ -122,20 +123,6 @@ PRBool nsBuiltinDecoder::Init(nsHTMLMediaElement* aElement)
return PR_TRUE;
}
void nsBuiltinDecoder::Stop()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
// The decode thread must die before the state machine can die.
// The state machine must die before the reader.
// The state machine must die before the decoder.
if (mStateMachineThread)
mStateMachineThread->Shutdown();
mStateMachineThread = nsnull;
mDecoderStateMachine = nsnull;
}
void nsBuiltinDecoder::Shutdown()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -161,17 +148,6 @@ void nsBuiltinDecoder::Shutdown()
ChangeState(PLAY_STATE_SHUTDOWN);
nsMediaDecoder::Shutdown();
// We can't destroy mDecoderStateMachine until mStateMachineThread is shut down.
// It's unsafe to Shutdown() the decode thread here, as
// nsIThread::Shutdown() may run events, such as JS event handlers,
// and we could be running at an unsafe time such as during element
// destruction.
// So we destroy the decoder on the main thread in an asynchronous event.
// See bug 468721.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsBuiltinDecoder::Stop);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
nsContentUtils::UnregisterShutdownObserver(this);
}
@ -229,7 +205,7 @@ nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
ChangeState(PLAY_STATE_LOADING);
return StartStateMachineThread();
return ScheduleStateMachineThread();
}
nsresult nsBuiltinDecoder::RequestFrameBufferLength(PRUint32 aLength)
@ -244,23 +220,25 @@ nsresult nsBuiltinDecoder::RequestFrameBufferLength(PRUint32 aLength)
return res;
}
nsresult nsBuiltinDecoder::StartStateMachineThread()
nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(mDecoderStateMachine,
"Must have state machine to start state machine thread");
if (mStateMachineThread) {
if (mShuttingDown)
return NS_OK;
}
nsresult rv = NS_NewThread(getter_AddRefs(mStateMachineThread));
NS_ENSURE_SUCCESS(rv, rv);
return mStateMachineThread->Dispatch(mDecoderStateMachine, NS_DISPATCH_NORMAL);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsBuiltinDecoderStateMachine* m =
static_cast<nsBuiltinDecoderStateMachine*>(mDecoderStateMachine.get());
return m->ScheduleStateMachine();
}
nsresult nsBuiltinDecoder::Play()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsresult res = StartStateMachineThread();
nsresult res = ScheduleStateMachineThread();
NS_ENSURE_SUCCESS(res,res);
if (mPlayState == PLAY_STATE_SEEKING) {
mNextState = PLAY_STATE_PLAYING;
@ -298,7 +276,7 @@ nsresult nsBuiltinDecoder::Seek(double aTime)
ChangeState(PLAY_STATE_SEEKING);
}
return StartStateMachineThread();
return ScheduleStateMachineThread();
}
nsresult nsBuiltinDecoder::PlaybackRateChanged()
@ -532,7 +510,7 @@ nsBuiltinDecoder::GetStatistics()
double nsBuiltinDecoder::ComputePlaybackRate(PRPackedBool* aReliable)
{
GetReentrantMonitor().AssertCurrentThreadIn();
NS_ASSERTION(NS_IsMainThread() || IsCurrentThread(mStateMachineThread),
NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
"Should be on main or state machine thread.");
PRInt64 length = mStream ? mStream->GetLength() : -1;
@ -545,7 +523,7 @@ double nsBuiltinDecoder::ComputePlaybackRate(PRPackedBool* aReliable)
void nsBuiltinDecoder::UpdatePlaybackRate()
{
NS_ASSERTION(NS_IsMainThread() || IsCurrentThread(mStateMachineThread),
NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
"Should be on main or state machine thread.");
GetReentrantMonitor().AssertCurrentThreadIn();
if (!mStream)
@ -871,7 +849,9 @@ void nsBuiltinDecoder::Resume(PRBool aForceBuffering)
void nsBuiltinDecoder::StopProgressUpdates()
{
NS_ASSERTION(IsCurrentThread(mStateMachineThread), "Should be on state machine thread.");
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
GetReentrantMonitor().AssertCurrentThreadIn();
mIgnoreProgressData = PR_TRUE;
if (mStream) {
mStream->SetReadMode(nsMediaCacheStream::MODE_METADATA);
@ -880,7 +860,9 @@ void nsBuiltinDecoder::StopProgressUpdates()
void nsBuiltinDecoder::StartProgressUpdates()
{
NS_ASSERTION(IsCurrentThread(mStateMachineThread), "Should be on state machine thread.");
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
GetReentrantMonitor().AssertCurrentThreadIn();
mIgnoreProgressData = PR_FALSE;
if (mStream) {
mStream->SetReadMode(nsMediaCacheStream::MODE_PLAYBACK);
@ -901,3 +883,7 @@ void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset)
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition);
}
PRBool nsBuiltinDecoder::OnStateMachineThread() const {
return IsCurrentThread(nsBuiltinDecoderStateMachine::GetStateMachineThread());
}

View File

@ -37,24 +37,28 @@
*
* ***** END LICENSE BLOCK ***** */
/*
Each video element based on nsBuiltinDecoder has at least one thread
dedicated to decoding video.
Each video element based on nsBuiltinDecoder has a state machine to manage
its play state and keep the current frame up to date. All state machines
share time in a single shared thread. Each decoder also has one thread
dedicated to decoding audio and video data. This thread is shutdown when
playback is paused. Each decoder also has a thread to push decoded audio
to the hardware. This thread is not created until playback starts, but
currently is not destroyed when paused, only when playback ends.
This thread (called the state machine thread owns the resources for
downloading and reading the media file. nsDecoderStateMachine is the
class that needs to be implemented and it gets run on the state
machine thread.
The decoder owns the resources for downloading the media file, and the
high level state. It holds an owning reference to the state machine
(a subclass of nsDecoderStateMachine; nsBuiltinDecoderStateMachine) that
owns all the resources related to decoding data, and manages the low level
decoding operations and A/V sync.
The state machine thread has one event that is dispatched to it (the
implementation of nsDecoderStateMachine) and that event runs for the
lifetime of the playback of the resource. State shared between threads
is synchronised with the main thread via a monitor held by the
nsBuiltinDecoder object.
The state machine thread event consist of a Run method which is an
infinite loop that performs the decoding operation and checks the
state that the state machine is in and processes operations on that
state.
Each state machine runs on the shared state machine thread. Every time some
action is required for a state machine, it is scheduled to run on the shared
the state machine thread. The state machine runs one "cycle" on the state
machine thread, and then returns. If necessary, it will schedule itself to
run again in future. While running this cycle, it must not block the
thread, as other state machines' events may need to run. State shared
between a state machine's threads is synchronised via the monitor owned
by its nsBuiltinDecoder object.
The Main thread controls the decode state machine by setting the value
of a mPlayState variable and notifying on the monitor based on the
@ -85,25 +89,37 @@ SHUTDOWN
State transition occurs when the Media Element calls the Play, Seek,
etc methods on the nsBuiltinDecoder object. When the transition
occurs nsBuiltinDecoder then calls the methods on the decoder state
machine object to cause it to behave appropriate to the play state.
machine object to cause it to behave as required by the play state.
State transitions will likely schedule the state machine to run to
affect the change.
An implementation of the nsDecoderStateMachine class is the event
that gets dispatched to the state machine thread. It has the following states:
that gets dispatched to the state machine thread. Each time the event is run,
the state machine must cycle the state machine once, and then return.
The state machine has the following states:
DECODING_METADATA
The media headers are being loaded, and things like framerate, etc are
being determined, and the first frame of audio/video data is being decoded.
DECODING
The decode and audio threads are started and video frames displayed at
the required time.
The decode has started. If the PlayState is PLAYING, the decode thread
should be alive and decoding video and audio frame, the audio thread
should be playing audio, and the state machine should run periodically
to update the video frames being displayed.
SEEKING
A seek operation is in progress.
A seek operation is in progress. The decode thread should be seeking.
BUFFERING
Decoding is paused while data is buffered for smooth playback.
Decoding is paused while data is buffered for smooth playback. If playback
is paused (PlayState transitions to PAUSED) we'll destory the decode thread.
COMPLETED
The resource has completed decoding, but not finished playback.
The resource has completed decoding, but possibly not finished playback.
The decode thread will be destroyed. Once playback finished, the audio
thread will also be destroyed.
SHUTDOWN
The decoder object is about to be destroyed.
The decoder object and its state machine are about to be destroyed.
Once the last state machine has been destroyed, the shared state machine
thread will also be destroyed. It will be recreated later if needed.
The following result in state transitions.
@ -157,41 +173,41 @@ player SHUTDOWN decoder SHUTDOWN
The general sequence of events is:
1) The video element calls Load on nsMediaDecoder. This creates the
state machine thread and starts the channel for downloading the
file. It instantiates and starts the nsDecoderStateMachine. The
state machine and starts the channel for downloading the
file. It instantiates and schedules the nsDecoderStateMachine. The
high level LOADING state is entered, which results in the decode
state machine to start decoding metadata. These are the headers
that give the video size, framerate, etc. It returns immediately
to the calling video element.
thread being created and starting to decode metadata. These are
the headers that give the video size, framerate, etc. Load() returns
immediately to the calling video element.
2) When the metadata has been loaded by the decode thread it will call
a method on the video element object to inform it that this step is
done, so it can do the things required by the video specification
at this stage. The decoder then continues to decode the first frame
2) When the metadata has been loaded by the decode thread, the state machine
will call a method on the video element object to inform it that this
step is done, so it can do the things required by the video specification
at this stage. The decode thread then continues to decode the first frame
of data.
3) When the first frame of data has been successfully decoded it calls
a method on the video element object to inform it that this step
has been done, once again so it can do the required things by the
video specification at this stage.
3) When the first frame of data has been successfully decoded the state
machine calls a method on the video element object to inform it that
this step has been done, once again so it can do the required things
by the video specification at this stage.
This results in the high level state changing to PLAYING or PAUSED
depending on any user action that may have occurred.
The decode thread plays audio and video, if the correct frame time
comes around and the decoder play state is PLAYING.
While the play state is PLAYING, the decode thread will decode
data, and the audio thread will push audio data to the hardware to
be played. The state machine will run periodically on the shared
state machine thread to ensure video frames are played at the
correct time; i.e. the state machine manages A/V sync.
a/v synchronisation is handled by the nsDecoderStateMachine implementation.
The Shutdown method on nsBuiltinDecoder closes the download channel, and
signals to the state machine that it should shutdown. The state machine
shuts down asynchronously, and will release the owning reference to the
state machine once its threads are shutdown.
The Shutdown method on nsBuiltinDecoder can spin the event loop as it
waits for threads to complete. Spinning the event loop is a bad thing
to happen during certain times like destruction of the media
element. To work around this the Shutdown method does nothing but
queue an event to the main thread to perform the actual Shutdown. This
way the shutdown can occur at a safe time.
The owning object of a nsBuiltinDecoder object *MUST* call Shutdown when
destroying the nsBuiltinDecoder object.
This means the owning object of a nsBuiltinDecoder object *MUST* call
Shutdown when destroying the nsBuiltinDecoder object.
*/
#if !defined(nsBuiltinDecoder_h_)
#define nsBuiltinDecoder_h_
@ -269,6 +285,9 @@ public:
// on the appropriate threads.
virtual PRBool OnDecodeThread() const = 0;
// Returns PR_TRUE if the current thread is the state machine thread.
virtual PRBool OnStateMachineThread() const = 0;
virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus() = 0;
// Cause state transitions. These methods obtain the decoder monitor
@ -425,19 +444,13 @@ class nsBuiltinDecoder : public nsMediaDecoder
// Tells our nsMediaStream to put all loads in the background.
virtual void MoveLoadsToBackground();
// Stop the state machine thread and drop references to the thread and
// state machine.
void Stop();
void AudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength, float aTime);
// Called by the state machine to notify the decoder that the duration
// has changed.
void DurationChanged();
PRBool OnStateMachineThread() {
return IsCurrentThread(mStateMachineThread);
}
PRBool OnStateMachineThread() const;
PRBool OnDecodeThread() const {
return mDecoderStateMachine->OnDecodeThread();
@ -567,9 +580,9 @@ public:
// Notifies the element that decoding has failed.
void DecodeError();
// Ensures the state machine thread is running, starting a new one
// if necessary.
nsresult StartStateMachineThread();
// Schedules the state machine to run one cycle on the shared state
// machine thread. Main thread only.
nsresult ScheduleStateMachineThread();
/******
* The following members should be accessed with the decoder lock held.
@ -590,9 +603,6 @@ public:
// time of the last decoded video frame).
nsChannelStatistics mPlaybackStatistics;
// Thread to manage playback state machine.
nsCOMPtr<nsIThread> mStateMachineThread;
// The current playback position of the media resource in units of
// seconds. This is updated approximately at the framerate of the
// video (if it is a video) or the callback period of the audio.

View File

@ -190,8 +190,7 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
}
nsBuiltinDecoderReader::nsBuiltinDecoderReader(nsBuiltinDecoder* aDecoder)
: mReentrantMonitor("media.decoderreader"),
mDecoder(aDecoder)
: mDecoder(aDecoder)
{
MOZ_COUNT_CTOR(nsBuiltinDecoderReader);
}
@ -214,7 +213,8 @@ nsresult nsBuiltinDecoderReader::ResetDecode()
VideoData* nsBuiltinDecoderReader::FindStartTime(PRInt64& aOutStartTime)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or decode thread.");
// Extract the start times of the bitstreams in order to calculate
// the duration.
@ -274,7 +274,6 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
PRBool skip = PR_FALSE;
eof = !DecodeVideoFrame(skip, 0);
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;
@ -299,7 +298,6 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
}
}
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;
@ -319,7 +317,6 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
while (!eof && mAudioQueue.GetSize() == 0) {
eof = !DecodeAudioData();
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;

View File

@ -398,12 +398,10 @@ private:
PRBool mEndOfStream;
};
// Encapsulates the decoding and reading of media data. Reading can be done
// on either the state machine thread (when loading and seeking) or on
// the reader thread (when it's reading and decoding). The reader encapsulates
// the reading state and maintains it's own monitor to ensure thread safety
// and correctness. Never hold the nsBuiltinDecoder's monitor when calling into
// this class.
// Encapsulates the decoding and reading of media data. Reading can only be
// done on the decode thread thread. Never hold the decoder monitor when
// calling into this class. Unless otherwise specified, methods and fields of
// this class can only be accessed on the decode thread.
class nsBuiltinDecoderReader : public nsRunnable {
public:
typedef mozilla::ReentrantMonitor ReentrantMonitor;
@ -452,10 +450,12 @@ public:
PRInt64 aEndTime,
PRInt64 aCurrentTime) = 0;
// Queue of audio samples. This queue is threadsafe.
// Queue of audio samples. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
MediaQueue<SoundData> mAudioQueue;
// Queue of video samples. This queue is threadsafe.
// Queue of video samples. This queue is threadsafe, and is accessed from
// the decoder, state machine, and main threads.
MediaQueue<VideoData> mVideoQueue;
// Populates aBuffered with the time ranges which are buffered. aStartTime
@ -492,16 +492,10 @@ protected:
return DecodeVideoFrame(f, 0);
}
// The lock which we hold whenever we read or decode. This ensures the thread
// safety of the reader and its data fields.
ReentrantMonitor mReentrantMonitor;
// Reference to the owning decoder object. Do not hold the
// reader's monitor when accessing this.
// Reference to the owning decoder object.
nsBuiltinDecoder* mDecoder;
// Stores presentation info required for playback. The reader's monitor
// must be held when accessing this.
// Stores presentation info required for playback.
nsVideoInfo mInfo;
};

File diff suppressed because it is too large Load Diff

View File

@ -37,11 +37,10 @@
*
* ***** END LICENSE BLOCK ***** */
/*
Each video element for a media file has two additional threads beyond
those needed by nsBuiltinDecoder.
Each video element for a media file has two threads:
1) The Audio thread writes the decoded audio data to the audio
hardware. This is done in a seperate thread to ensure that the
hardware. This is done in a separate thread to ensure that the
audio hardware gets a constant stream of data without
interruption due to decoding or display. At some point
libsydneyaudio will be refactored to have a callback interface
@ -49,31 +48,27 @@ those needed by nsBuiltinDecoder.
needed.
2) The decode thread. This thread reads from the media stream and
decodes the Theora and Vorbis data. It places the decoded data in
a queue for the other threads to pull from.
decodes the Theora and Vorbis data. It places the decoded data into
queues for the other threads to pull from.
All file reads and seeks must occur on either the state machine thread
or the decode thread. Synchronisation is done via a monitor owned by
nsBuiltinDecoder.
All file reads, seeks, and all decoding must occur on the decode thread.
Synchronisation of state between the thread is done via a monitor owned
by nsBuiltinDecoder.
The decode thread and the audio thread are created and destroyed in
the state machine thread. When playback needs to occur they are
created and events dispatched to them to start them. These events exit
when decoding is completed or no longer required (during seeking or
shutdown).
The lifetime of the decode and audio threads is controlled by the state
machine when it runs on the shared state machine thread. When playback
needs to occur they are created and events dispatched to them to run
them. These events exit when decoding/audio playback is completed or
no longer required.
The decode thread has its own monitor to ensure that its internal
state is independent of the other threads, and to ensure that it's not
hogging the nsBuiltinDecoder monitor while decoding.
a/v synchronisation is handled by the state machine thread. It
examines the audio playback time and compares this to the next frame
in the queue of frames. If it is time to play the video frame it is
then displayed.
A/V synchronisation is handled by the state machine. It examines the audio
playback time and compares this to the next frame in the queue of video
frames. If it is time to play the video frame it is then displayed, otherwise
it schedules the state machine to run again at the time of the next frame.
Frame skipping is done in the following ways:
1) The state machine thread will skip all frames in the video queue whose
1) The state machine will skip all frames in the video queue whose
display time is less than the current audio time. This ensures
the correct frame for the current time is always displayed.
@ -86,28 +81,30 @@ Frame skipping is done in the following ways:
will be decoding video data that won't be displayed due
to the decode thread dropping the frame immediately.
YCbCr conversion is done on the decode thread when it is time to display
the video frame. This means frames that are skipped will not have the
YCbCr conversion done, improving playback.
When hardware accelerated graphics is not available, YCbCr conversion
is done on the decode thread when video frames are decoded.
The decode thread pushes decoded audio and videos frames into two
separate queues - one for audio and one for video. These are kept
separate to make it easy to constantly feed audio data to the sound
hardware while allowing frame skipping of video data. These queues are
threadsafe, and neither the decode, audio, or state machine thread should
threadsafe, and neither the decode, audio, or state machine should
be able to monopolize them, and cause starvation of the other threads.
Both queues are bounded by a maximum size. When this size is reached
the decode thread will no longer decode video or audio depending on the
queue that has reached the threshold.
queue that has reached the threshold. If both queues are full, the decode
thread will wait on the decoder monitor.
When the decode queues are full (they've reaced their maximum size) and
the decoder is not in PLAYING play state, the state machine may opt
to shut down the decode thread in order to conserve resources.
During playback the audio thread will be idle (via a Wait() on the
monitor) if the audio queue is empty. Otherwise it constantly pops an
item off the queue and plays it with a blocking write to the audio
monitor) if the audio queue is empty. Otherwise it constantly pops
sound data off the queue and plays it with a blocking write to the audio
hardware (via nsAudioStream and libsydneyaudio).
The decode thread idles if the video queue is empty or if it is
not yet time to display the next frame.
*/
#if !defined(nsBuiltinDecoderStateMachine_h__)
#define nsBuiltinDecoderStateMachine_h__
@ -119,21 +116,17 @@ not yet time to display the next frame.
#include "nsAudioAvailableEventManager.h"
#include "nsHTMLMediaElement.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsITimer.h"
/*
The playback state machine class. This manages the decoding in the
nsBuiltinDecoderReader on the decode thread, seeking and in-sync-playback on the
The state machine class. This manages the decoding and seeking in the
nsBuiltinDecoderReader on the decode thread, and A/V sync on the shared
state machine thread, and controls the audio "push" thread.
All internal state is synchronised via the decoder monitor. NotifyAll
on the monitor is called when the state of the state machine is changed
by the main thread. The following changes to state cause a notify:
mState and data related to that state changed (mSeekTime, etc)
Metadata Loaded
First Frame Loaded
Frame decoded
data pushed or popped from the video and audio queues
All internal state is synchronised via the decoder monitor. State changes
are either propagated by NotifyAll on the monitor (typically when state
changes need to be propagated to non-state machine threads) or by scheduling
the state machine to run another cycle on the shared state machine thread.
See nsBuiltinDecoder.h for more details.
*/
@ -172,13 +165,7 @@ public:
virtual void UpdatePlaybackPosition(PRInt64 aTime);
virtual void StartBuffering();
// Load metadata Called on the state machine thread. The decoder monitor must be held with
// exactly one lock count.
virtual void LoadMetadata();
// State machine thread run function. Polls the state, sends frames to be
// displayed at appropriate times, and generally manages the decode.
// State machine thread run function. Defers to RunStateMachine().
NS_IMETHOD Run();
// This is called on the state machine thread and audio thread.
@ -214,25 +201,28 @@ public:
// Functions used by assertions to ensure we're calling things
// on the appropriate threads.
PRBool OnAudioThread() {
PRBool OnAudioThread() const {
return IsCurrentThread(mAudioThread);
}
PRBool OnStateMachineThread() {
return mDecoder->OnStateMachineThread();
PRBool OnStateMachineThread() const {
return IsCurrentThread(GetStateMachineThread());
}
// Decode loop, called on the decode thread.
void DecodeLoop();
// The decoder object that created this state machine. The decoder
// always outlives us since it controls our lifetime. This is accessed
// read only on the AV, state machine, audio and main thread.
nsBuiltinDecoder* mDecoder;
// The decoder object that created this state machine. The state machine
// holds a strong reference to the decoder to ensure that the decoder stays
// alive once media element has started the decoder shutdown process, and has
// dropped its reference to the decoder. This enables the state machine to
// keep using the decoder's monitor until the state machine has finished
// shutting down, without fear of the monitor being destroyed. After
// shutting down, the state machine will then release this reference,
// causing the decoder to be destroyed. This is accessed on the decode,
// state machine, audio and main threads.
nsRefPtr<nsBuiltinDecoder> mDecoder;
// The decoder monitor must be obtained before modifying this state.
// NotifyAll on the monitor must be called when the state is changed by
// the main thread so the decoder thread can wake up.
// NotifyAll on the monitor must be called when the state is changed so
// that interested threads can wake up and alter behaviour if appropriate
// Accessed on state machine, audio, main, and AV thread.
State mState;
@ -257,6 +247,23 @@ public:
// Accessed on the main and state machine threads.
virtual void SetFrameBufferLength(PRUint32 aLength);
// Returns the shared state machine thread.
static nsIThread* GetStateMachineThread();
// Schedules the shared state machine thread to run the state machine.
// If the state machine thread is the currently running the state machine,
// we wait until that has completely finished before running the state
// machine again.
nsresult ScheduleStateMachine();
// Schedules the shared state machine thread to run the state machine
// in aUsecs microseconds from now, if it's not already scheduled to run
// earlier, in which case the request is discarded.
nsresult ScheduleStateMachine(PRInt64 aUsecs);
// Timer function to implement ScheduleStateMachine(aUsecs).
void TimeoutExpired();
protected:
// Returns PR_TRUE if we've got less than aAudioUsecs microseconds of decoded
@ -290,14 +297,14 @@ protected:
// wait for a specified time, and that the myriad of Notify()s we do on
// the decoder monitor don't cause the audio thread to be starved. aUsecs
// values of less than 1 millisecond are rounded up to 1 millisecond
// (see bug 651023). The decoder monitor must be held.
// (see bug 651023). The decoder monitor must be held. Called only on the
// audio thread.
void Wait(PRInt64 aUsecs);
// Dispatches an asynchronous event to update the media element's ready state.
void UpdateReadyState();
// Resets playback timing data. Called when we seek, on the state machine
// thread.
// Resets playback timing data. Called when we seek, on the decode thread.
void ResetPlayback();
// Returns the audio clock, if we have audio, or -1 if we don't.
@ -316,9 +323,8 @@ protected:
// machine thread, caller must hold the decoder lock.
void UpdatePlaybackPositionInternal(PRInt64 aTime);
// Performs YCbCr to RGB conversion, and pushes the image down the
// rendering pipeline. Called on the state machine thread. The decoder
// monitor must not be held when calling this.
// Pushes the image down the rendering pipeline. Called on the shared state
// machine thread. The decoder monitor must *not* be held when calling this.
void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
// If we have video, display a video frame if it's time for display has
@ -344,36 +350,35 @@ protected:
// queued here. Called on the audio thread.
PRUint32 PlayFromAudioQueue(PRUint64 aSampleOffset, PRUint32 aChannels);
// Stops the decode threads. The decoder monitor must be held with exactly
// Stops the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
void StopDecodeThreads();
void StopDecodeThread();
// Starts the decode threads. The decoder monitor must be held with exactly
// Stops the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartDecodeThreads();
void StopAudioThread();
// Starts the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartDecodeThread();
// Starts the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartAudioThread();
// The main loop for the audio thread. Sent to the thread as
// an nsRunnableMethod. This continually does blocking writes to
// to audio stream to play audio data.
void AudioLoop();
// Stop or pause playback of media. This has two modes, denoted by
// aMode being either AUDIO_PAUSE or AUDIO_SHUTDOWN.
//
// AUDIO_PAUSE: Suspends the audio stream to be resumed later.
// This does not close the OS based audio stream
//
// AUDIO_SHUTDOWN: Closes and destroys the audio stream and
// releases any OS resources.
//
// The decoder monitor must be held with exactly one lock count. Called
// on the state machine thread.
enum eStopMode {AUDIO_PAUSE, AUDIO_SHUTDOWN};
void StopPlayback(eStopMode aMode);
// Sets internal state which causes playback of media to pause.
// The decoder monitor must be held. Called on the main, state machine,
// and decode threads.
void StopPlayback();
// Resume playback of media. Must be called with the decode monitor held.
// This resumes a paused audio stream. The decoder monitor must be held with
// exactly one lock count. Called on the state machine thread.
// Sets internal state which causes playback of media to begin or resume.
// Must be called with the decode monitor held. Called on the state machine
// and decode threads.
void StartPlayback();
// Moves the decoder into decoding state. Called on the state machine
@ -400,14 +405,42 @@ protected:
// which has been pushed to the audio hardware for playback. Note that after
// calling this, the audio hardware may play some of the audio pushed to
// hardware, so this can only be used as a upper bound. The decoder monitor
// must be held when calling this. Called on the decoder thread.
// must be held when calling this. Called on the decode thread.
PRInt64 GetDecodedAudioDuration();
// ReentrantMonitor on mAudioStream. This monitor must be held in
// order to delete or use the audio stream. This stops us destroying
// the audio stream while it's being used on another thread
// (typically when it's being written to on the audio thread).
ReentrantMonitor mAudioReentrantMonitor;
// Load metadata. Called on the decode thread. The decoder monitor
// must be held with exactly one lock count.
nsresult DecodeMetadata();
// Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
// must be held with exactly one lock count.
void DecodeSeek();
// Decode loop, decodes data until EOF or shutdown.
// Called on the decode thread.
void DecodeLoop();
// Decode thread run function. Determines which of the Decode*() functions
// to call.
void DecodeThreadRun();
// State machine thread run function. Defers to RunStateMachine().
nsresult CallRunStateMachine();
// Performs one "cycle" of the state machine. Polls the state, and may send
// a video frame to be displayed, and generally manages the decode. Called
// periodically via timer to ensure the video stays in sync.
nsresult RunStateMachine();
PRBool IsStateMachineScheduled() const {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
return !mTimeout.IsNull() || mRunAgain;
}
// Returns PR_TRUE if we're not playing and the decode thread has filled its
// decode buffers and is waiting. We can shut the decode thread down in this
// case as it may not be needed again.
PRBool IsPausedAndDecoderWaiting();
// The size of the decoded YCbCr frame.
// Accessed on state machine thread.
@ -423,6 +456,15 @@ protected:
// Thread for decoding video in background. The "decode thread".
nsCOMPtr<nsIThread> mDecodeThread;
// Timer to call the state machine Run() method. Used by
// ScheduleStateMachine(). Access protected by decoder monitor.
nsCOMPtr<nsITimer> mTimer;
// Timestamp at which the next state machine Run() method will be called.
// If this is non-null, a call to Run() is scheduled, either by a timer,
// or via an event. Access protected by decoder monitor.
TimeStamp mTimeout;
// The time that playback started from the system clock. This is used for
// timing the presentation of video frames when there's no audio.
// Accessed only via the state machine thread.
@ -441,23 +483,24 @@ protected:
// Start time of the media, in microseconds. This is the presentation
// time of the first sample decoded from the media, and is used to calculate
// duration and as a bounds for seeking. Accessed on state machine and
// main thread. Access controlled by decoder monitor.
// duration and as a bounds for seeking. Accessed on state machine, decode,
// and main threads. Access controlled by decoder monitor.
PRInt64 mStartTime;
// Time of the last page in the media, in microseconds. This is the
// end time of the last sample in the media. Accessed on state
// machine and main thread. Access controlled by decoder monitor.
// machine, decode, and main threads. Access controlled by decoder monitor.
PRInt64 mEndTime;
// Position to seek to in microseconds when the seek state transition occurs.
// The decoder monitor lock must be obtained before reading or writing
// this value. Accessed on main and state machine thread.
// this value. Accessed on main and decode thread.
PRInt64 mSeekTime;
// The audio stream resource. Used on the state machine, audio, and
// main threads. You must hold the mAudioReentrantMonitor, and must
// NOT hold the decoder monitor when using the audio stream!
// The audio stream resource. Used on the state machine, and audio threads.
// This is created and destroyed on the audio thread, while holding the
// decoder monitor, so if this is used off the audio thread, you must
// first acquire the decoder monitor and check that it is non-null.
nsRefPtr<nsAudioStream> mAudioStream;
// The reader, don't call its methods with the decoder monitor held.
@ -516,9 +559,20 @@ protected:
// the media index/metadata. Accessed on the state machine thread.
PRPackedBool mGotDurationFromMetaData;
// PR_FALSE while decode threads should be running. Accessed on audio,
// state machine and decode threads. Syncrhonised by decoder monitor.
PRPackedBool mStopDecodeThreads;
// PR_FALSE while decode thread should be running. Accessed state machine
// and decode threads. Syncrhonised by decoder monitor.
PRPackedBool mStopDecodeThread;
// PR_TRUE when the decode thread run function has finished, but the thread
// has not necessarily been shut down yet. This can happen if we switch
// from COMPLETED state to SEEKING before the state machine has a chance
// to run in the COMPLETED state and shutdown the decode thread.
// Synchronised by the decoder monitor.
PRPackedBool mDecodeThreadIdle;
// PR_FALSE while audio thread should be running. Accessed state machine
// and audio threads. Syncrhonised by decoder monitor.
PRPackedBool mStopAudioThread;
// If this is PR_TRUE while we're in buffering mode, we can exit early,
// as it's likely we may be able to playback. This happens when we enter
@ -527,6 +581,26 @@ protected:
// Synchronised via decoder monitor.
PRPackedBool mQuickBuffering;
// PR_TRUE if the shared state machine thread is currently running this
// state machine.
PRPackedBool mIsRunning;
// PR_TRUE if we should run the state machine again once the current
// state machine run has finished.
PRPackedBool mRunAgain;
// PR_TRUE if we've dispatched an event to run the state machine. It's
// imperative that we don't dispatch multiple events to run the state
// machine at the same time, as our code assume all events are synchronous.
// If we dispatch multiple events, the second event can run while the
// first is shutting down a thread, causing inconsistent state.
PRPackedBool mDispatchedRunEvent;
// PR_TRUE if the decode thread has gone filled its buffers and is now
// waiting to be awakened before it continues decoding. Synchronized
// by the decoder monitor.
PRPackedBool mDecodeThreadWaiting;
private:
// Manager for queuing and dispatching MozAudioAvailable events. The
// event manager is accessed from the state machine and audio threads,

View File

@ -65,20 +65,6 @@ class nsTimeRanges;
#define FRAMEBUFFER_LENGTH_MIN 512
#define FRAMEBUFFER_LENGTH_MAX 16384
// Shuts down a thread asynchronously.
class ShutdownThreadEvent : public nsRunnable
{
public:
ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {}
~ShutdownThreadEvent() {}
NS_IMETHOD Run() {
mThread->Shutdown();
return NS_OK;
}
private:
nsCOMPtr<nsIThread> mThread;
};
// All methods of nsMediaDecoder must be called from the main thread only
// with the exception of GetImageContainer, SetVideoData and GetStatistics,
// which can be called from any thread.

View File

@ -140,15 +140,13 @@ nsresult nsOggReader::Init(nsBuiltinDecoderReader* aCloneDonor) {
nsresult nsOggReader::ResetDecode()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nsresult res = NS_OK;
if (NS_FAILED(nsBuiltinDecoderReader::ResetDecode())) {
res = NS_ERROR_FAILURE;
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Discard any previously buffered packets/pages.
ogg_sync_reset(&mOggState);
if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
@ -157,7 +155,6 @@ nsresult nsOggReader::ResetDecode()
if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
res = NS_ERROR_FAILURE;
}
}
return res;
}
@ -178,8 +175,7 @@ PRBool nsOggReader::ReadHeaders(nsOggCodecState* aState)
nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on play state machine thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// We read packets until all bitstreams have read all their header packets.
// We record the offset of the first non-header page so that we know
@ -318,8 +314,7 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
}
PRInt64 duration = 0;
if (NS_SUCCEEDED(mSkeletonState->GetDuration(tracks, duration))) {
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->GetStateMachine()->SetDuration(duration);
LOG(PR_LOG_DEBUG, ("Got duration from Skeleton index %lld", duration));
}
@ -327,8 +322,7 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
}
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
nsMediaStream* stream = mDecoder->GetCurrentStream();
if (mDecoder->GetStateMachine()->GetDuration() == -1 &&
@ -402,9 +396,7 @@ nsresult nsOggReader::DecodeVorbis(ogg_packet* aPacket) {
PRBool nsOggReader::DecodeAudioData()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on playback or decode thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
NS_ASSERTION(mVorbisState!=0, "Need Vorbis state to decode audio");
// Read the next data packet. Skip any non-data packets we encounter.
@ -480,9 +472,6 @@ nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold)
b.mPlanes[i].mStride = buffer[i].stride;
}
// Need the monitor to be held to be able to use mInfo. This
// is held by our caller.
mReentrantMonitor.AssertCurrentThreadIn();
VideoData *v = VideoData::Create(mInfo,
mDecoder->GetImageContainer(),
mPageOffset,
@ -506,9 +495,7 @@ nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold)
PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or AV thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
@ -557,9 +544,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
{
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on play state machine or decode thread.");
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
int ret = 0;
while((ret = ogg_sync_pageseek(&mOggState, aPage)) <= 0) {
@ -597,9 +582,7 @@ PRInt64 nsOggReader::ReadOggPage(ogg_page* aPage)
ogg_packet* nsOggReader::NextOggPacket(nsOggCodecState* aCodecState)
{
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on play state machine or decode thread.");
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
if (!aCodecState || !aCodecState->mActive) {
return nsnull;
@ -642,8 +625,7 @@ GetChecksum(ogg_page* page)
PRInt64 nsOggReader::RangeStartTime(PRInt64 aOffset)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nsMediaStream* stream = mDecoder->GetCurrentStream();
NS_ENSURE_TRUE(stream != nsnull, nsnull);
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
@ -665,9 +647,8 @@ struct nsAutoOggSyncState {
PRInt64 nsOggReader::RangeEndTime(PRInt64 aEndOffset)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or decode thread.");
nsMediaStream* stream = mDecoder->GetCurrentStream();
NS_ENSURE_TRUE(stream != nsnull, -1);
@ -797,9 +778,7 @@ PRInt64 nsOggReader::RangeEndTime(PRInt64 aStartOffset,
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nsTArray<nsByteRange> cached;
nsresult res = mDecoder->GetCurrentStream()->GetCachedRanges(cached);
NS_ENSURE_SUCCESS(res, res);
@ -838,8 +817,7 @@ nsOggReader::SelectSeekRange(const nsTArray<SeekRange>& ranges,
PRInt64 aEndTime,
PRBool aExact)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
PRInt64 so = 0;
PRInt64 eo = mDecoder->GetCurrentStream()->GetLength();
PRInt64 st = aStartTime;
@ -977,8 +955,7 @@ nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget,
PRBool skip = PR_FALSE;
eof = !DecodeVideoFrame(skip, 0);
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;
}
@ -1052,9 +1029,7 @@ nsresult nsOggReader::Seek(PRInt64 aTarget,
PRInt64 aEndTime,
PRInt64 aCurrentTime)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
nsresult res;
nsMediaStream* stream = mDecoder->GetCurrentStream();
@ -1072,8 +1047,7 @@ nsresult nsOggReader::Seek(PRInt64 aTarget,
NS_ASSERTION(aStartTime != -1, "mStartTime should be known");
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->UpdatePlaybackPosition(aStartTime);
}
} else if (CanDecodeToTarget(aTarget, aCurrentTime)) {
@ -1183,8 +1157,7 @@ nsresult nsOggReader::SeekBisection(PRInt64 aTarget,
const SeekRange& aRange,
PRUint32 aFuzz)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nsresult res;
nsMediaStream* stream = mDecoder->GetCurrentStream();

View File

@ -71,15 +71,11 @@ public:
virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold);
virtual PRBool HasAudio()
{
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
virtual PRBool HasAudio() {
return mVorbisState != 0 && mVorbisState->mActive;
}
virtual PRBool HasVideo()
{
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
virtual PRBool HasVideo() {
return mTheoraState != 0 && mTheoraState->mActive;
}
@ -89,9 +85,7 @@ public:
private:
PRBool HasSkeleton()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
PRBool HasSkeleton() {
return mSkeletonState != 0 && mSkeletonState->mActive;
}

View File

@ -123,7 +123,6 @@ var gPlayTests = [
{ name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
];
// Converts a path/filename to a file:// URI which we can load from disk.

View File

@ -29,7 +29,8 @@ function startTest() {
function seekStarted() {
if (completed)
return false;
ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
ok(v.currentTime >= seekTime - 0.1,
"Video currentTime should be around " + seekTime + ": " + v.currentTime + " (seeking)");
v.pause();
startPassed = true;
return false;
@ -43,7 +44,7 @@ function seekEnded() {
// Since we were playing, and we only paused asynchronously, we can't be
// sure that we paused before the seek finished, so we may have played
// ahead arbitrarily far.
ok(t >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + t);
ok(t >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + t + " (seeked)");
v.play();
endPassed = true;
seekFlagEnd = v.seeking;

View File

@ -41,7 +41,7 @@ function ended(e) {
} catch (e) {
caught = e.code == DOMException.INDEX_SIZE_ERR;
}
is(caught, true, "Should throw INDEX_SIZE_ERR on under start bounds range");
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under start bounds range");
caught = false;
try {
@ -49,7 +49,7 @@ function ended(e) {
} catch (e) {
caught = e.code == DOMException.INDEX_SIZE_ERR;
}
is(caught, true, "Should throw INDEX_SIZE_ERR on under end bounds range");
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under end bounds range");
caught = false;
try {
@ -57,7 +57,7 @@ function ended(e) {
} catch (e) {
caught = e.code == DOMException.INDEX_SIZE_ERR;
}
is(caught, true, "Should throw INDEX_SIZE_ERR on over start bounds range");
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over start bounds range");
caught = false;
try {
@ -65,8 +65,9 @@ function ended(e) {
} catch (e) {
caught = e.code == DOMException.INDEX_SIZE_ERR;
}
is(caught, true, "Should throw INDEX_SIZE_ERR on over end bounds range");
is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over end bounds range");
v.src = "";
v.parentNode.removeChild(v);
manager.finished(v.token);

View File

@ -33,6 +33,7 @@ function canPlayThrough(e) {
ok(true, "Got canplaythrough after seek for " + v._name);
v._finished = true;
v.parentNode.removeChild(v);
v.src = "";
manager.finished(v.token);
}
}

View File

@ -152,8 +152,7 @@ nsresult nsWaveReader::Init(nsBuiltinDecoderReader* aCloneDonor)
nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
PRBool loaded = LoadRIFFChunk() && LoadFormatChunk() && FindDataOffset();
if (!loaded) {
@ -167,8 +166,7 @@ nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
*aInfo = mInfo;
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->GetStateMachine()->SetDuration(
static_cast<PRInt64>(BytesToTime(GetDataLength()) * USECS_PER_S));
@ -178,9 +176,7 @@ nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo)
PRBool nsWaveReader::DecodeAudioData()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine thread or decode thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
PRInt64 pos = GetPosition() - mWavePCMOffset;
PRInt64 len = GetDataLength();
@ -246,18 +242,14 @@ PRBool nsWaveReader::DecodeAudioData()
PRBool nsWaveReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or decode thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return PR_FALSE;
}
nsresult nsWaveReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget));
if (NS_FAILED(ResetDecode())) {
return NS_ERROR_FAILURE;

View File

@ -209,8 +209,7 @@ void nsWebMReader::Cleanup()
nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo)
{
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nestegg_io io;
io.read = webm_read;
@ -225,8 +224,7 @@ nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo)
uint64_t duration = 0;
r = nestegg_duration(mContext, &duration);
if (r == 0) {
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->GetStateMachine()->SetDuration(duration / NS_PER_USEC);
}
@ -411,7 +409,7 @@ ogg_packet nsWebMReader::InitOggPacket(unsigned char* aData,
PRBool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
{
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
int r = 0;
unsigned int count = 0;
@ -589,9 +587,8 @@ nsReturnRef<NesteggPacketHolder> nsWebMReader::NextPacket(TrackType aTrackType)
PRBool nsWebMReader::DecodeAudioData()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine thread or decode thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
nsAutoRef<NesteggPacketHolder> holder(NextPacket(AUDIO));
if (!holder) {
mAudioQueue.Finish();
@ -604,9 +601,7 @@ PRBool nsWebMReader::DecodeAudioData()
PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
"Should be on state machine or decode thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
@ -652,7 +647,6 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
}
mVideoPackets.PushFront(next_holder.disown());
} else {
ReentrantMonitorAutoExit exitMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
nsBuiltinDecoderStateMachine* s =
static_cast<nsBuiltinDecoderStateMachine*>(mDecoder->GetStateMachine());
@ -766,9 +760,8 @@ PRBool nsWebMReader::CanDecodeToTarget(PRInt64 aTarget,
nsresult nsWebMReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTime,
PRInt64 aCurrentTime)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread.");
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget));
if (CanDecodeToTarget(aTarget, aCurrentTime)) {
LOG(PR_LOG_DEBUG, ("%p Seek target (%lld) is close to current time (%lld), "

View File

@ -143,13 +143,13 @@ public:
virtual PRBool HasAudio()
{
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return mHasAudio;
}
virtual PRBool HasVideo()
{
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return mHasVideo;
}

View File

@ -242,22 +242,35 @@ nsSVGFilterElement::GetStringInfo()
NS_ARRAY_LENGTH(sStringInfo));
}
void
nsSVGFilterElement::DidAnimateLength(PRUint8 aAttrEnum)
inline static void DidAnimateAttr(nsSVGFilterElement *aFilterElement)
{
// nsSVGFilterFrame does not implement a useful AttributeChanged
nsIFrame* frame = GetPrimaryFrame();
// nsSVGFilterFrame doesn't implement a useful AttributeChanged
nsIFrame* frame = aFilterElement->GetPrimaryFrame();
if (frame) {
nsSVGEffects::InvalidateRenderingObservers(frame);
}
}
void
nsSVGFilterElement::DidAnimateLength(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
void
nsSVGFilterElement::DidAnimateIntegerPair(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
void
nsSVGFilterElement::DidAnimateEnum(PRUint8 aAttrEnum)
{
// nsSVGFilterFrame does not implement a useful AttributeChanged
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
nsSVGEffects::InvalidateRenderingObservers(frame);
}
DidAnimateAttr(this);
}
void
nsSVGFilterElement::DidAnimateString(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}

View File

@ -89,7 +89,9 @@ protected:
virtual StringAttributesInfo GetStringInfo();
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateIntegerPair(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
virtual void DidAnimateString(PRUint8 aAttrEnum);
enum { X, Y, WIDTH, HEIGHT };
nsSVGLength2 mLengthAttributes[4];

View File

@ -310,7 +310,8 @@ inline static void DidAnimateAttr(Element *aFilterPrimitive)
}
}
inline static void DidAnimateAttrViaParent(Element *aFilterPrimitive) {
inline static void DidAnimateAttrViaParent(Element *aFilterPrimitive)
{
// No frame, use parent's
NS_ASSERTION(!aFilterPrimitive->GetPrimaryFrame(), "Not expecting a frame");
nsIContent *parent = aFilterPrimitive->GetFlattenedTreeParent();

View File

@ -79,7 +79,6 @@
#include "nsPIDOMWindow.h"
#include "nsIViewManager.h"
#include "nsDOMError.h"
#include "nsIMenuFrame.h"
using namespace mozilla;

View File

@ -85,6 +85,7 @@ EXPORTS = \
nsWrapperCache.h \
nsContentPermissionHelper.h \
nsStructuredCloneContainer.h \
nsDOMMemoryReporter.h \
$(NULL)
CPPSRCS = \

View File

@ -1574,7 +1574,7 @@ static const nsConstructorFuncMapData kConstructorFuncMap[] =
{
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Worker, nsDOMWorker::NewWorker)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ChromeWorker, nsDOMWorker::NewChromeWorker)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFile::NewFile)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
};

View File

@ -41,6 +41,40 @@
#include "nsIMemoryReporter.h"
/**
* Helper methods for the DOM Memory Reporter.
*/
namespace mozilla {
namespace dom {
namespace MemoryReporter {
/**
* It will compute the basic size of an object. This means the size of the
* object itself plus everything owned by its superclasses. This will not
* include the size of objects owned by this objects (which have to be
* manually added to ::SizeOf), but does include the size of any pointers
* to those objects stored in this object.
*/
template <class TypeCurrent, class TypeParent>
inline PRInt64 GetBasicSize(const TypeCurrent* const obj) {
return obj->TypeParent::SizeOf() - sizeof(TypeParent)
+ sizeof(TypeCurrent);
}
}
}
}
/**
* Helper macros to declare/implement SizeOf() method for DOM objects.
*/
#define NS_DECL_DOM_MEMORY_REPORTER_SIZEOF \
virtual PRInt64 SizeOf() const;
#define NS_DECL_AND_IMPL_DOM_MEMORY_REPORTER_SIZEOF(TypeCurrent, TypeParent) \
virtual PRInt64 SizeOf() const { \
return mozilla::dom::MemoryReporter::GetBasicSize<TypeCurrent, \
TypeParent>(this); \
}
class nsDOMMemoryReporter: public nsIMemoryReporter {
public:
NS_DECL_ISUPPORTS

View File

@ -1026,6 +1026,8 @@ nsGlobalWindow::~nsGlobalWindow()
CleanUp(PR_TRUE);
NS_ASSERTION(!mHasDeviceMotion, "Window still registered with device motion.");
#ifdef DEBUG
nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
#endif

View File

@ -383,6 +383,7 @@ public:
virtual NS_HIDDEN_(void) SetHasOrientationEventListener();
virtual NS_HIDDEN_(void) MaybeUpdateTouchState();
virtual NS_HIDDEN_(void) UpdateTouchState();
virtual NS_HIDDEN_(PRBool) DispatchCustomEvent(const char *aEventName);
// nsIDOMStorageWindow
NS_DECL_NSIDOMSTORAGEWINDOW
@ -729,8 +730,6 @@ protected:
return GetParentInternal() != nsnull;
}
PRBool DispatchCustomEvent(const char *aEventName);
// If aLookForCallerOnJSStack is true, this method will look at the JS stack
// to determine who the caller is. If it's false, it'll use |this| as the
// caller.

View File

@ -1833,7 +1833,9 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
#ifdef NS_FUNCTION_TIMER
{
JSObject *obj = static_cast<JSObject *>(aHandler);
JSString *id = JS_GetFunctionId(static_cast<JSFunction *>(JS_GetPrivate(mContext, obj)));
if (obj->isFunctionProxy())
obj = obj->unwrap(NULL);
JSString *id = JS_GetFunctionId(GET_FUNCTION_PRIVATE(mContext, obj));
JSAutoByteString bytes;
const char *name = !id ? "anonymous" : bytes.encode(mContext, id) ? bytes.ptr() : "<error>";
NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME, __LINE__, name);

View File

@ -80,8 +80,8 @@ class nsIArray;
class nsPIWindowRoot;
#define NS_PIDOMWINDOW_IID \
{ 0x6c05ae9d, 0x4ad1, 0x4e92, \
{ 0x9c, 0x95, 0xd3, 0x54, 0xea, 0x0f, 0xb9, 0x48 } }
{ 0xa595249b, 0x1e74, 0x467e, \
{ 0x92, 0x56, 0x58, 0xff, 0x07, 0x1b, 0xc2, 0x96 } }
class nsPIDOMWindow : public nsIDOMWindowInternal
{
@ -579,6 +579,12 @@ public:
*/
PRUint64 WindowID() const { return mWindowID; }
/**
* Dispatch a custom event with name aEventName targeted at this window.
* Returns whether the default action should be performed.
*/
virtual PRBool DispatchCustomEvent(const char *aEventName) = 0;
protected:
// The nsPIDOMWindow constructor. The aOuterWindow argument should
// be null if and only if the created window itself is an outer

View File

@ -50,17 +50,17 @@
* http://www.whatwg.org/specs/web-apps/current-work/
*/
[scriptable, uuid(cf8a8744-ec3b-474e-8f2b-8def3da2344a)]
[scriptable, uuid(4bedb0a0-f901-4c61-a93a-a43c1b7674d4)]
interface nsIDOMHTMLImageElement : nsIDOMHTMLElement
{
attribute DOMString alt;
attribute DOMString src;
attribute DOMString useMap;
attribute boolean isMap;
attribute long width;
attribute long height;
readonly attribute long naturalWidth;
readonly attribute long naturalHeight;
attribute unsigned long width;
attribute unsigned long height;
readonly attribute unsigned long naturalWidth;
readonly attribute unsigned long naturalHeight;
readonly attribute boolean complete;

View File

@ -87,7 +87,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
mMIMEType(nsnull),
mOwner(nsnull),
mCurrentPluginEvent(nsnull),
#if defined(MOZ_X11) || defined(XP_WIN)
#if defined(MOZ_X11) || defined(XP_WIN) || defined(XP_MACOSX)
mUsePluginLayersPref(PR_TRUE)
#else
mUsePluginLayersPref(PR_FALSE)

View File

@ -1477,7 +1477,7 @@ void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
// If the renderer is backed by an IOSurface, resize it as required.
mIOSurface = nsIOSurface::CreateIOSurface(aWidth, aHeight);
if (mIOSurface) {
nsIOSurface *attachSurface = nsIOSurface::LookupSurface(
nsRefPtr<nsIOSurface> attachSurface = nsIOSurface::LookupSurface(
mIOSurface->GetIOSurfaceID());
if (attachSurface) {
mCARenderer.AttachIOSurface(attachSurface);

View File

@ -324,7 +324,7 @@ private:
NP_Port mQDPluginPortCopy;
#endif
PRInt32 mInCGPaintLevel;
nsIOSurface *mIOSurface;
nsRefPtr<nsIOSurface> mIOSurface;
nsCARenderer mCARenderer;
CGColorSpaceRef mColorProfile;
static nsCOMPtr<nsITimer> *sCATimer;

View File

@ -75,6 +75,7 @@ EXPORTS_mozilla/plugins = \
PluginScriptableObjectUtils-inl.h \
PluginInstanceChild.h \
PluginInstanceParent.h \
PluginUtilsOSX.h \
AStream.h \
BrowserStreamChild.h \
BrowserStreamParent.h \

View File

@ -186,7 +186,7 @@ PluginInstanceChild::~PluginInstanceChild()
::CGContextRelease(mShContext);
}
if (mCGLayer) {
mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
}
#endif
}
@ -844,7 +844,7 @@ PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
PaintTracker pt;
NPCocoaEvent evcopy = event.event;
nsIOSurface* surf = nsIOSurface::LookupSurface(surfaceid);
nsRefPtr<nsIOSurface> surf = nsIOSurface::LookupSurface(surfaceid);
if (!surf) {
NS_ERROR("Invalid IOSurface.");
*handled = false;
@ -2577,44 +2577,18 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
return true;
#else // XP_MACOSX
if (mCurrentIOSurface &&
(mCurrentIOSurface->GetWidth() != mWindow.width ||
mCurrentIOSurface->GetHeight() != mWindow.height) ) {
mCurrentIOSurface = nsnull;
}
if (!mCARenderer.isInit() || !mCurrentIOSurface) {
if (!mCurrentIOSurface) {
mCurrentIOSurface = nsIOSurface::CreateIOSurface(mWindow.width, mWindow.height);
nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
}
if (!mCurrentIOSurface) {
NS_WARNING("Failed to allocate IOSurface");
return false;
}
nsIOSurface *rendererSurface = nsIOSurface::LookupSurface(mCurrentIOSurface->GetIOSurfaceID());
if (!rendererSurface) {
NS_WARNING("Failed to lookup IOSurface");
return false;
}
mCARenderer.AttachIOSurface(rendererSurface);
if (!mDoubleBufferCARenderer.HasCALayer()) {
void *caLayer = nsnull;
if (mDrawingModel == NPDrawingModelCoreGraphics) {
if (mCGLayer) {
mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
mCGLayer = nsnull;
}
if (!mCGLayer) {
caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this);
if (!caLayer) {
PLUGIN_LOG_DEBUG(("GetCGLayer failed."));
return false;
}
}
mCGLayer = caLayer;
} else {
NPError result = mPluginIface->getvalue(GetNPP(),
@ -2626,11 +2600,28 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
return false;
}
}
mDoubleBufferCARenderer.SetCALayer(caLayer);
}
if (mDoubleBufferCARenderer.HasFrontSurface() &&
(mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width ||
mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height) ) {
mDoubleBufferCARenderer.ClearFrontSurface();
}
if (!mDoubleBufferCARenderer.HasFrontSurface()) {
bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface(mWindow.width,
mWindow.height);
if (!allocSurface) {
PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface"));
return false;
}
mCARenderer.SetupRenderer(caLayer, mWindow.width, mWindow.height);
// Flash needs to have the window set again after this step
if (mPluginIface->setwindow)
(void) mPluginIface->setwindow(&mData, &mWindow);
nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
}
return true;
@ -3030,7 +3021,7 @@ PluginInstanceChild::ShowPluginFrame()
return false;
}
#ifdef XP_MACOSX
#ifdef MOZ_WIDGET_COCOA
// We can't use the thebes code with CoreAnimation so we will
// take a different code path.
if (mDrawingModel == NPDrawingModelCoreAnimation ||
@ -3041,6 +3032,11 @@ PluginInstanceChild::ShowPluginFrame()
return true;
}
if (!mDoubleBufferCARenderer.HasFrontSurface()) {
NS_ERROR("CARenderer not initialized for rendering");
return false;
}
// Clear accRect here to be able to pass
// test_invalidate_during_plugin_paint test
nsIntRect rect = mAccumulatedInvalidRect;
@ -3049,33 +3045,30 @@ PluginInstanceChild::ShowPluginFrame()
// Fix up old invalidations that might have been made when our
// surface was a different size
rect.IntersectRect(rect,
nsIntRect(0, 0, mCurrentIOSurface->GetWidth(), mCurrentIOSurface->GetHeight()));
if (!mCARenderer.isInit()) {
NS_ERROR("CARenderer not initialized");
return false;
}
nsIntRect(0, 0,
mDoubleBufferCARenderer.GetFrontSurfaceWidth(),
mDoubleBufferCARenderer.GetFrontSurfaceHeight()));
if (mDrawingModel == NPDrawingModelCoreGraphics) {
mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect);
}
mCARenderer.Render(mWindow.width, mWindow.height, nsnull);
mDoubleBufferCARenderer.Render();
NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
(uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
SurfaceDescriptor currSurf;
currSurf = IOSurfaceDescriptor(mCurrentIOSurface->GetIOSurfaceID());
currSurf = IOSurfaceDescriptor(mDoubleBufferCARenderer.GetFrontSurfaceID());
mHasPainted = true;
// Unused
SurfaceDescriptor returnSurf;
if (!SendShow(r, currSurf, &returnSurf)) {
return false;
}
SwapSurfaces();
return true;
} else {
NS_ERROR("Unsupported drawing model for async layer rendering");
@ -3511,19 +3504,32 @@ PluginInstanceChild::SwapSurfaces()
mBackSurfaceActor = tmpactor;
#endif
#ifdef MOZ_WIDGET_COCOA
mDoubleBufferCARenderer.SwapSurfaces();
// Outdated back surface... not usable anymore due to changed plugin size.
// Dropping obsolete surface
if (mCurrentSurface && mBackSurface &&
(mCurrentSurface->GetSize() != mBackSurface->GetSize() ||
mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) {
ClearCurrentSurface();
if (mDoubleBufferCARenderer.HasFrontSurface() &&
mDoubleBufferCARenderer.HasBackSurface() &&
(mDoubleBufferCARenderer.GetFrontSurfaceWidth() !=
mDoubleBufferCARenderer.GetBackSurfaceWidth() ||
mDoubleBufferCARenderer.GetFrontSurfaceHeight() !=
mDoubleBufferCARenderer.GetBackSurfaceHeight())) {
mDoubleBufferCARenderer.ClearFrontSurface();
}
#endif //MOZ_WIDGET_COCOA
}
void
PluginInstanceChild::ClearCurrentSurface()
{
mCurrentSurface = nsnull;
#ifdef MOZ_WIDGET_COCOA
if (mDoubleBufferCARenderer.HasFrontSurface()) {
mDoubleBufferCARenderer.ClearFrontSurface();
}
#endif
#ifdef XP_WIN
if (mCurrentSurfaceActor) {
PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
@ -3542,6 +3548,7 @@ PluginInstanceChild::ClearAllSurfaces()
NPRect r = { 0, 0, 1, 1 };
SendShow(r, temp, &temp);
}
if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface))
DeallocShmem(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem());
if (gfxSharedImageSurface::IsSharedImage(mBackSurface))
@ -3560,8 +3567,8 @@ PluginInstanceChild::ClearAllSurfaces()
}
#endif
#ifdef XP_MACOSX
if (mCurrentIOSurface) {
#ifdef MOZ_WIDGET_COCOA
if (mDoubleBufferCARenderer.HasBackSurface()) {
// Get last surface back, and drop it
SurfaceDescriptor temp = null_t();
NPRect r = { 0, 0, 1, 1 };
@ -3573,7 +3580,8 @@ PluginInstanceChild::ClearAllSurfaces()
mCGLayer = nsnull;
}
mCurrentIOSurface = nsnull;
mDoubleBufferCARenderer.ClearFrontSurface();
mDoubleBufferCARenderer.ClearBackSurface();
#endif
}

View File

@ -46,8 +46,11 @@
#if defined(OS_WIN)
#include "mozilla/gfx/SharedDIBWin.h"
#elif defined(MOZ_WIDGET_COCOA)
#include "PluginUtilsOSX.h"
#include "nsCoreAnimationSupport.h"
#include "base/timer.h"
using namespace mozilla::plugins::PluginUtilsOSX;
#endif
#include "npfunctions.h"
@ -524,7 +527,7 @@ private:
#ifdef XP_MACOSX
// Current IOSurface available for rendering
// We can't use thebes gfxASurface like other platforms.
nsAutoPtr<nsIOSurface> mCurrentIOSurface;
nsDoubleBufferCARenderer mDoubleBufferCARenderer;
#endif
// (Not to be confused with mBackSurface). This is a recent copy

View File

@ -519,19 +519,22 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
else if (newSurface.type() == SurfaceDescriptor::TIOSurfaceDescriptor) {
IOSurfaceDescriptor iodesc = newSurface.get_IOSurfaceDescriptor();
nsIOSurface *newIOSurface = nsIOSurface::LookupSurface(iodesc.surfaceId());
nsRefPtr<nsIOSurface> newIOSurface = nsIOSurface::LookupSurface(iodesc.surfaceId());
if (!newIOSurface) {
NS_WARNING("Got bad IOSurfaceDescriptor in RecvShow");
return false;
}
if (mFrontIOSurface)
*prevSurface = IOSurfaceDescriptor(mFrontIOSurface->GetIOSurfaceID());
else
*prevSurface = null_t();
mFrontIOSurface = newIOSurface;
RecvNPN_InvalidateRect(updatedRect);
*prevSurface = null_t();
PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)",
mFrontSurface.get()));

View File

@ -357,8 +357,8 @@ private:
size_t mShHeight;
CGColorSpaceRef mShColorSpace;
int16_t mDrawingModel;
nsAutoPtr<nsIOSurface> mIOSurface;
nsAutoPtr<nsIOSurface> mFrontIOSurface;
nsRefPtr<nsIOSurface> mIOSurface;
nsRefPtr<nsIOSurface> mFrontIOSurface;
#endif // definied(MOZ_WIDGET_COCOA)
// ObjectFrame layer wrapper

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