mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Merge m-c to s-c
This commit is contained in:
commit
feed89ded5
@ -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;
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
||||
|
@ -500,3 +500,6 @@ statuspanel[label=""] {
|
||||
.panel-inner-arrowcontentfooter[footertype="promobox"] {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
|
||||
}
|
||||
|
||||
/* highlighter */
|
||||
%include highlighter.css
|
||||
|
@ -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.
|
||||
|
36
browser/base/content/highlighter.css
Normal file
36
browser/base/content/highlighter.css
Normal 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;
|
||||
}
|
@ -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>
|
@ -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.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);
|
||||
this.highlighterContainer.appendChild(veilBox);
|
||||
this.highlighterContainer.appendChild(controlsBox);
|
||||
|
||||
iframe.setAttribute("src", "chrome://browser/content/highlighter.xhtml");
|
||||
stack.appendChild(this.highlighterContainer);
|
||||
|
||||
div.appendChild(iframe);
|
||||
stack.appendChild(div);
|
||||
this.iframe = iframe;
|
||||
this.iframeContainer = div;
|
||||
this.browser.addEventListener("resize", this, true);
|
||||
this.browser.addEventListener("scroll", this, true);
|
||||
|
||||
this.handleResize();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 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,54 +472,28 @@ 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();
|
||||
win.focus();
|
||||
}
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopPropagation();
|
||||
if (aEvent.button == 0) {
|
||||
let win = aEvent.target.ownerDocument.defaultView;
|
||||
InspectorUI.stopInspecting();
|
||||
win.focus();
|
||||
}
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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))
|
||||
|
@ -41,8 +41,10 @@ var progressListener4 = {
|
||||
onLocationChange: function onLocationChange() {
|
||||
ok(expectListener4, "didn't call progressListener4 for the first location change");
|
||||
gBrowser.removeProgressListener(this);
|
||||
gBrowser.addTab();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
executeSoon(function () {
|
||||
gBrowser.addTab();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
33
browser/base/content/test/browser_minimize.js
Normal file
33
browser/base/content/test/browser_minimize.js
Normal 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();
|
||||
}
|
@ -110,9 +110,11 @@ function runNextTest() {
|
||||
|
||||
let onHidden = onHiddenArray.shift();
|
||||
info("[Test #" + gTestIndex + "] popup hidden (" + onHiddenArray.length + " hides remaining)");
|
||||
onHidden.call(nextTest, this);
|
||||
if (!onHiddenArray.length)
|
||||
goNext();
|
||||
executeSoon(function () {
|
||||
onHidden.call(nextTest, this);
|
||||
if (!onHiddenArray.length)
|
||||
goNext();
|
||||
});
|
||||
}, onHiddenArray.length);
|
||||
info("[Test #" + gTestIndex + "] added listeners; panel state: " + PopupNotifications.isPanelOpen);
|
||||
}
|
||||
@ -739,4 +741,4 @@ function dismissNotification(popup) {
|
||||
executeSoon(function () {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -84,13 +84,17 @@ var gTabsListener = {
|
||||
|
||||
// Reset arrays.
|
||||
this._loadedURIs.length = 0;
|
||||
// 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);
|
||||
executeSoon(function () {
|
||||
// Close all tabs.
|
||||
while (gBrowser.tabs.length > 1)
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
// Test finished. This will move to the next one.
|
||||
waitForFocus(gCurrentTest.finish, gBrowser.ownerDocument.defaultView);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,6 @@
|
||||
#else
|
||||
@BINPATH@/mozsqlt3@DLL_SUFFIX@
|
||||
#endif
|
||||
@BINPATH@/README.txt
|
||||
@BINPATH@/blocklist.xml
|
||||
#ifdef XP_UNIX
|
||||
@BINPATH@/run-mozilla.sh
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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@
|
||||
|
@ -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)"
|
||||
|
31
configure.in
31
configure.in
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -52,64 +52,65 @@
|
||||
|
||||
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 == PR_UINT64_MAX) {
|
||||
CheckedUint64 length = 0;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 len = mBlobs.Length();
|
||||
for (i = 0; i < len; i++) {
|
||||
nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
|
||||
PRUint64 l = 0;
|
||||
|
||||
nsresult rv = blob->GetSize(&l);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
length += l;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(length.valid(), NS_ERROR_FAILURE);
|
||||
|
||||
if (mLength) {
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
mLength = length.value();
|
||||
}
|
||||
|
||||
CheckedUint64 length = 0;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 len = mBlobs.Length();
|
||||
for (i = 0; i < len; i++) {
|
||||
nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
|
||||
PRUint64 l = 0;
|
||||
|
||||
rv = blob->GetSize(&l);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
length += l;
|
||||
}
|
||||
|
||||
if (!length.valid())
|
||||
return 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,
|
||||
getter_AddRefs(firstBlob));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = blob->MozSlice(skipStart, skipStart + upperBound,
|
||||
aContentType, 3,
|
||||
getter_AddRefs(firstBlob));
|
||||
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,
|
||||
getter_AddRefs(lastBlob));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = blob->MozSlice(0, length, aContentType, 3,
|
||||
getter_AddRefs(lastBlob));
|
||||
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)
|
||||
|
@ -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();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(mimeType, mContentType);
|
||||
}
|
||||
*aSize = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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,9 +229,9 @@ ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::MozSlice(PRInt64 aStart, PRInt64 aEnd,
|
||||
const nsAString& aContentType, PRUint8 optional_argc,
|
||||
nsIDOMBlob **aBlob)
|
||||
nsDOMFileBase::MozSlice(PRInt64 aStart, PRInt64 aEnd,
|
||||
const nsAString& aContentType, PRUint8 optional_argc,
|
||||
nsIDOMBlob **aBlob)
|
||||
{
|
||||
*aBlob = nsnull;
|
||||
|
||||
@ -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));
|
||||
|
||||
return NS_OK;
|
||||
*aBlob = CreateSlice((PRUint64)aStart, (PRUint64)(aEnd - aStart),
|
||||
aContentType).get();
|
||||
|
||||
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,9 +291,9 @@ nsDOMFile::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetSendInfo(nsIInputStream** aBody,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset)
|
||||
nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -368,12 +313,103 @@ 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,
|
||||
JSContext* aCx,
|
||||
JSObject* aObj,
|
||||
PRUint32 aArgc,
|
||||
jsval* aArgv)
|
||||
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,
|
||||
jsval* aArgv)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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(),
|
||||
|
@ -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] + ")";
|
||||
|
@ -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();
|
||||
|
@ -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,15 +2784,17 @@ 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(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_MEASURE,
|
||||
nsnull,
|
||||
0,
|
||||
&totalWidthCoord);
|
||||
nsBidi bidiEngine;
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_MEASURE,
|
||||
nsnull,
|
||||
0,
|
||||
&totalWidthCoord,
|
||||
&bidiEngine);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -2892,15 +2893,16 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
processor.mThebes = ctx;
|
||||
|
||||
rv = bidiUtils->ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull);
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull,
|
||||
&bidiEngine);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -2929,15 +2931,16 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
ApplyStyle(STYLE_FILL);
|
||||
}
|
||||
|
||||
rv = bidiUtils->ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull);
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull,
|
||||
&bidiEngine);
|
||||
|
||||
// this needs to be restored before function can return
|
||||
if (doUseIntermediateSurface) {
|
||||
|
@ -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,15 +3247,17 @@ 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(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_MEASURE,
|
||||
nsnull,
|
||||
0,
|
||||
&totalWidthCoord);
|
||||
nsBidi bidiEngine;
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_MEASURE,
|
||||
nsnull,
|
||||
0,
|
||||
&totalWidthCoord,
|
||||
&bidiEngine);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -3348,15 +3348,16 @@ nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
|
||||
// don't ever need to measure the bounding box twice
|
||||
processor.mDoMeasureBoundingBox = PR_FALSE;
|
||||
|
||||
rv = bidiUtils->ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull);
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
presShell->GetPresContext(),
|
||||
processor,
|
||||
nsBidiPresUtils::MODE_DRAW,
|
||||
nsnull,
|
||||
0,
|
||||
nsnull,
|
||||
&bidiEngine);
|
||||
|
||||
|
||||
mTarget->SetTransform(oldTransform);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -1987,11 +1987,11 @@ void nsHTMLMediaElement::NetworkError()
|
||||
|
||||
void nsHTMLMediaElement::DecodeError()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nsnull;
|
||||
}
|
||||
if (mIsLoadingFromSourceChildren) {
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nsnull;
|
||||
}
|
||||
mError = nsnull;
|
||||
if (mSourceLoadCandidate) {
|
||||
DispatchAsyncSourceError(mSourceLoadCandidate);
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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,14 +976,12 @@ nsHTMLTableElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
if (aResult.ParseSpecialIntValue(aValue)) {
|
||||
// treat 0 width as auto
|
||||
nsAttrValue::ValueType type = aResult.Type();
|
||||
if ((type == nsAttrValue::eInteger &&
|
||||
aResult.GetIntegerValue() == 0) ||
|
||||
(type == nsAttrValue::ePercent &&
|
||||
aResult.GetPercentValue() == 0.0f)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
return !((type == nsAttrValue::eInteger &&
|
||||
aResult.GetIntegerValue() == 0) ||
|
||||
(type == nsAttrValue::ePercent &&
|
||||
aResult.GetPercentValue() == 0.0f));
|
||||
}
|
||||
return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::align) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
58
content/html/content/test/test_bug586786.html
Normal file
58
content/html/content/test/test_bug586786.html
Normal 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>
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -183,8 +159,8 @@ nsBuiltinDecoder::~nsBuiltinDecoder()
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
|
||||
nsIStreamListener** aStreamListener,
|
||||
nsMediaDecoder* aCloneDonor)
|
||||
nsIStreamListener** aStreamListener,
|
||||
nsMediaDecoder* aCloneDonor)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (aStreamListener) {
|
||||
@ -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());
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
a/v synchronisation is handled by the nsDecoderStateMachine implementation.
|
||||
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.
|
||||
|
||||
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 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 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.
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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 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.
|
||||
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.
|
||||
|
||||
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,26 +201,29 @@ 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.
|
||||
// Accessed on state machine, audio, main, and AV thread.
|
||||
// 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;
|
||||
|
||||
nsresult GetBuffered(nsTimeRanges* aBuffered);
|
||||
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -140,23 +140,20 @@ 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())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
// Discard any previously buffered packets/pages.
|
||||
ogg_sync_reset(&mOggState);
|
||||
if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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), "
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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();
|
||||
|
@ -79,7 +79,6 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -85,6 +85,7 @@ EXPORTS = \
|
||||
nsWrapperCache.h \
|
||||
nsContentPermissionHelper.h \
|
||||
nsStructuredCloneContainer.h \
|
||||
nsDOMMemoryReporter.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1477,8 +1477,8 @@ 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(
|
||||
mIOSurface->GetIOSurfaceID());
|
||||
nsRefPtr<nsIOSurface> attachSurface = nsIOSurface::LookupSurface(
|
||||
mIOSurface->GetIOSurfaceID());
|
||||
if (attachSurface) {
|
||||
mCARenderer.AttachIOSurface(attachSurface);
|
||||
} else {
|
||||
|
@ -324,7 +324,7 @@ private:
|
||||
NP_Port mQDPluginPortCopy;
|
||||
#endif
|
||||
PRInt32 mInCGPaintLevel;
|
||||
nsIOSurface *mIOSurface;
|
||||
nsRefPtr<nsIOSurface> mIOSurface;
|
||||
nsCARenderer mCARenderer;
|
||||
CGColorSpaceRef mColorProfile;
|
||||
static nsCOMPtr<nsITimer> *sCATimer;
|
||||
|
@ -75,6 +75,7 @@ EXPORTS_mozilla/plugins = \
|
||||
PluginScriptableObjectUtils-inl.h \
|
||||
PluginInstanceChild.h \
|
||||
PluginInstanceParent.h \
|
||||
PluginUtilsOSX.h \
|
||||
AStream.h \
|
||||
BrowserStreamChild.h \
|
||||
BrowserStreamParent.h \
|
||||
|
@ -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);
|
||||
|
||||
caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this);
|
||||
if (!caLayer) {
|
||||
return false;
|
||||
if (!caLayer) {
|
||||
PLUGIN_LOG_DEBUG(("GetCGLayer failed."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mCGLayer = caLayer;
|
||||
} else {
|
||||
NPError result = mPluginIface->getvalue(GetNPP(),
|
||||
@ -2626,13 +2600,30 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
if (mPluginIface->setwindow)
|
||||
(void) mPluginIface->setwindow(&mData, &mWindow);
|
||||
|
||||
nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
|
||||
mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user