зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to electrolysis to pick up bug 515436.
This commit is contained in:
Коммит
960781ec85
|
@ -408,15 +408,6 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
eARIASelectable,
|
||||
eARIAReadonly
|
||||
},
|
||||
{
|
||||
"section",
|
||||
nsIAccessibleRole::ROLE_SECTION,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates
|
||||
},
|
||||
{
|
||||
"separator",
|
||||
nsIAccessibleRole::ROLE_SEPARATOR,
|
||||
|
|
|
@ -96,6 +96,7 @@ _TEST_FILES =\
|
|||
test_events_doc.html \
|
||||
test_events_draganddrop.html \
|
||||
test_events_flush.html \
|
||||
test_events_focus.html \
|
||||
test_events_focus.xul \
|
||||
test_events_mutation.html \
|
||||
test_events_tree.xul \
|
||||
|
|
|
@ -91,6 +91,7 @@ function unregisterA11yEventListener(aEventType, aEventHandler)
|
|||
listenA11yEvents(false);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event queue
|
||||
|
||||
|
@ -106,15 +107,6 @@ const INVOKER_ACTION_FAILED = 1;
|
|||
*/
|
||||
const DO_NOT_FINISH_TEST = 1;
|
||||
|
||||
/**
|
||||
* Common invoker checker (see eventSeq of eventQueue).
|
||||
*/
|
||||
function invokerChecker(aEventType, aTarget)
|
||||
{
|
||||
this.type = aEventType;
|
||||
this.target = aTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates event queue for the given event type. The queue consists of invoker
|
||||
* objects, each of them generates the event of the event type. When queue is
|
||||
|
@ -539,6 +531,9 @@ function eventQueue(aEventType)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Action sequence
|
||||
|
||||
/**
|
||||
* Deal with action sequence. Used when you need to execute couple of actions
|
||||
* each after other one.
|
||||
|
@ -586,6 +581,168 @@ function sequence()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event queue invokers
|
||||
|
||||
/**
|
||||
* Invokers defined below take a checker object implementing 'check' method
|
||||
* which will be called when proper event is handled. Invokers listen default
|
||||
* event type registered in event queue object.
|
||||
*
|
||||
* Note, you don't need to initialize 'target' and 'type' members of checker
|
||||
* object. The 'target' member will be initialized by invoker object and you are
|
||||
* free to use it in 'check' method.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Click invoker.
|
||||
*/
|
||||
function synthClick(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aChecker);
|
||||
|
||||
this.invoke = function synthClick_invoke()
|
||||
{
|
||||
// Scroll the node into view, otherwise synth click may fail.
|
||||
this.DOMNode.scrollIntoView(true);
|
||||
|
||||
synthesizeMouse(this.DOMNode, 1, 1, {});
|
||||
}
|
||||
|
||||
this.getID = function synthFocus_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " click";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General key press invoker.
|
||||
*/
|
||||
function synthKey(aNodeOrID, aKey, aArgs, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aChecker);
|
||||
|
||||
this.invoke = function synthKey_invoke()
|
||||
{
|
||||
synthesizeKey(this.mKey, this.mArgs);
|
||||
}
|
||||
|
||||
this.getID = function synthFocus_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " '" + this.mKey + "' key";
|
||||
}
|
||||
|
||||
this.mKey = aKey;
|
||||
this.mArgs = aArgs ? aArgs : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab key invoker.
|
||||
*/
|
||||
function synthTab(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", { shiftKey: false },
|
||||
aChecker);
|
||||
|
||||
this.getID = function synthTabTest_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " tab";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift tab key invoker.
|
||||
*/
|
||||
function synthShiftTab(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", { shiftKey: true },
|
||||
aChecker);
|
||||
|
||||
this.getID = function synthTabTest_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " shift tab";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Down arrow key invoker.
|
||||
*/
|
||||
function synthDownKey(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, "VK_DOWN", null, aChecker);
|
||||
|
||||
this.getID = function synthDownKey_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " key down";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right arrow key invoker.
|
||||
*/
|
||||
function synthRightKey(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", null, aChecker);
|
||||
|
||||
this.getID = function synthRightKey_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " key right";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus invoker.
|
||||
*/
|
||||
function synthFocus(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aChecker);
|
||||
|
||||
this.invoke = function synthFocus_invoke()
|
||||
{
|
||||
this.DOMNode.focus();
|
||||
}
|
||||
|
||||
this.getID = function synthFocus_getID()
|
||||
{
|
||||
return prettyName(aNodeOrID) + " focus";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all invoker.
|
||||
*/
|
||||
function synthSelectAll(aNodeOrID, aChecker)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aChecker);
|
||||
|
||||
this.invoke = function synthSelectAll_invoke()
|
||||
{
|
||||
if (this.DOMNode instanceof Components.interfaces.nsIDOMHTMLInputElement)
|
||||
this.DOMNode.select();
|
||||
else
|
||||
window.getSelection().selectAllChildren(this.DOMNode);
|
||||
}
|
||||
|
||||
this.getID = function synthSelectAll_getID()
|
||||
{
|
||||
return aNodeOrID + " selectall";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event queue checkers
|
||||
|
||||
/**
|
||||
* Common invoker checker (see eventSeq of eventQueue).
|
||||
*/
|
||||
function invokerChecker(aEventType, aTarget)
|
||||
{
|
||||
this.type = aEventType;
|
||||
this.target = aTarget;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Private implementation details.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -741,3 +898,22 @@ function sequenceItem(aProcessor, aEventType, aTarget, aItemID)
|
|||
|
||||
this.queue.push(invoker);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event queue invokers
|
||||
|
||||
/**
|
||||
* Invoker base class for prepare an action.
|
||||
*/
|
||||
function synthAction(aNodeOrID, aChecker)
|
||||
{
|
||||
this.DOMNode = getNode(aNodeOrID);
|
||||
aChecker.target = this.DOMNode;
|
||||
|
||||
this.check = function synthAction_check(aEvent)
|
||||
{
|
||||
aChecker.check(aEvent);
|
||||
}
|
||||
|
||||
this.getID = function synthAction_getID() { return aNodeOrID + " action"; }
|
||||
}
|
||||
|
|
|
@ -56,6 +56,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=469688
|
|||
// test gEmptyRoleMap
|
||||
testRole("cell", ROLE_NOTHING);
|
||||
|
||||
// abstract roles
|
||||
var abstract_roles = ["composite", "landmark", "structure", "widget",
|
||||
"window", "input", "range", "select", "section",
|
||||
"sectionhead"];
|
||||
for (a in abstract_roles)
|
||||
testRole(abstract_roles[a], ROLE_SECTION);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -111,5 +118,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=469688
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- user agents must not map abstract roles to platform API -->
|
||||
<!-- test abstract base type roles -->
|
||||
<div role="composite" id="composite">composite</div>
|
||||
<div role="landmark" id="landmark">landmark</div>
|
||||
<div role="roletype" id="roletype">roletype</div>
|
||||
<div role="structure" id="structure">structure</div>
|
||||
<div role="widget" id="widget">widget</div>
|
||||
<div role="window" id="window">window</div>
|
||||
<!-- test abstract input roles -->
|
||||
<div role="input" id="input">input</div>
|
||||
<div role="range" id="range">range</div>
|
||||
<div role="select" id="select">select</div>
|
||||
<!-- test abstract structure roles -->
|
||||
<div role="section" id="section">section</div>
|
||||
<div role="sectionhead" id="sectionhead">sectionhead</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -20,135 +20,37 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
/**
|
||||
* Invoker base class.
|
||||
* Generic checker.
|
||||
*/
|
||||
function synthAction(aNodeOrID, aCaretOffset)
|
||||
function checker(aCaretOffset)
|
||||
{
|
||||
this.DOMNode = getNode(aNodeOrID);
|
||||
|
||||
this.check = function synthAction_check(aEvent)
|
||||
this.check = function checker_check(aEvent)
|
||||
{
|
||||
is(aEvent.QueryInterface(nsIAccessibleCaretMoveEvent).caretOffset,
|
||||
this.caretOffset,
|
||||
"Wrong caret offset for " + aNodeOrID);
|
||||
aCaretOffset,
|
||||
"Wrong caret offset for " + prettyName(aEvent.target));
|
||||
}
|
||||
|
||||
this.getID = function synthAction_getID() { return aNodeOrID + " action"; }
|
||||
|
||||
this.caretOffset = aCaretOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click invoker.
|
||||
* Click checker.
|
||||
*/
|
||||
function synthClick(aNodeOrID, aCaretOffset,
|
||||
aExtraNodeOrID, aExtraCaretOffset)
|
||||
function clickChecker(aCaretOffset, aExtraNodeOrID, aExtraCaretOffset)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aCaretOffset);
|
||||
this.__proto__ = new checker(aCaretOffset);
|
||||
|
||||
this.extraNode = getNode(aExtraNodeOrID);
|
||||
this.extraCaretOffset = aExtraCaretOffset;
|
||||
|
||||
this.invoke = function synthClick_invoke()
|
||||
{
|
||||
// Scroll the node into view, otherwise synth click may fail.
|
||||
this.DOMNode.scrollIntoView(true);
|
||||
|
||||
synthesizeMouse(this.DOMNode, 1, 1, {});
|
||||
}
|
||||
|
||||
this.check = function synthFocus_check(aEvent)
|
||||
this.check = function clickChecker_check(aEvent)
|
||||
{
|
||||
this.__proto__.check(aEvent);
|
||||
|
||||
if (this.extraNode) {
|
||||
var acc = getAccessible(this.extraNode, [nsIAccessibleText]);
|
||||
is(acc.caretOffset, this.extraCaretOffset,
|
||||
is(acc.caretOffset, aExtraCaretOffset,
|
||||
"Wrong caret offset for " + aExtraNodeOrID);
|
||||
}
|
||||
}
|
||||
|
||||
this.getID = function synthFocus_getID() { return aNodeOrID + " click"; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Key press invokers.
|
||||
*/
|
||||
function synthKey(aNodeOrID, aCaretOffset, aKey, aArgs)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aCaretOffset);
|
||||
|
||||
this.invoke = function synthKey_invoke()
|
||||
{
|
||||
synthesizeKey(this.mKey, this.mArgs);
|
||||
}
|
||||
|
||||
this.mKey = aKey;
|
||||
this.mArgs = aArgs ? aArgs : {};
|
||||
}
|
||||
|
||||
function synthTabTest(aNodeOrID, aCaretOffset, aBackTab)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, aCaretOffset,
|
||||
"VK_TAB", {shiftKey: aBackTab});
|
||||
|
||||
this.getID = function synthTabTest_getID() { return aNodeOrID + " tab"; }
|
||||
}
|
||||
|
||||
function synthDownKey(aNodeOrID, aCaretOffset)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, aCaretOffset, "VK_DOWN");
|
||||
|
||||
this.getID = function synthDownKey_getID()
|
||||
{
|
||||
return aNodeOrID + " key down";
|
||||
}
|
||||
}
|
||||
|
||||
function synthRightKey(aNodeOrID, aCaretOffset)
|
||||
{
|
||||
this.__proto__ = new synthKey(aNodeOrID, aCaretOffset, "VK_RIGHT");
|
||||
|
||||
this.getID = function synthRightKey_getID()
|
||||
{
|
||||
return aNodeOrID + " key right";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus invoker.
|
||||
*/
|
||||
function synthFocus(aNodeOrID, aCaretOffset)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aCaretOffset);
|
||||
|
||||
this.invoke = function synthFocus_invoke()
|
||||
{
|
||||
this.DOMNode.focus();
|
||||
}
|
||||
|
||||
this.getID = function synthFocus_getID() { return aNodeOrID + " focus"; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all invoker.
|
||||
*/
|
||||
function synthSelectAll(aNodeOrID, aCaretOffset)
|
||||
{
|
||||
this.__proto__ = new synthAction(aNodeOrID, aCaretOffset);
|
||||
|
||||
this.invoke = function synthSelectAll_invoke()
|
||||
{
|
||||
if (this.DOMNode instanceof Components.interfaces.nsIDOMHTMLInputElement)
|
||||
this.DOMNode.select();
|
||||
else
|
||||
window.getSelection().selectAllChildren(this.DOMNode);
|
||||
}
|
||||
|
||||
this.getID = function synthSelectAll_getID()
|
||||
{
|
||||
return aNodeOrID + " selectall";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,26 +79,27 @@
|
|||
gQueue = new eventQueue(nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED);
|
||||
|
||||
var id = "textbox";
|
||||
gQueue.push(new synthFocus(id, 5));
|
||||
gQueue.push(new synthSelectAll(id, 5));
|
||||
gQueue.push(new synthClick(id, 0));
|
||||
gQueue.push(new synthRightKey(id, 1));
|
||||
gQueue.push(new synthFocus(id, new checker(5)));
|
||||
gQueue.push(new synthSelectAll(id, new checker(5)));
|
||||
gQueue.push(new synthClick(id, new checker(0)));
|
||||
gQueue.push(new synthRightKey(id, new checker(1)));
|
||||
|
||||
id = "textarea";
|
||||
gQueue.push(new synthClick(id, 0));
|
||||
gQueue.push(new synthRightKey(id, 1));
|
||||
gQueue.push(new synthDownKey(id, 12));
|
||||
gQueue.push(new synthClick(id, new checker(0)));
|
||||
gQueue.push(new synthRightKey(id, new checker(1)));
|
||||
gQueue.push(new synthDownKey(id, new checker(12)));
|
||||
|
||||
id = "p";
|
||||
gQueue.push(new synthClick(id, 0));
|
||||
gQueue.push(new synthRightKey(id, 1));
|
||||
gQueue.push(new synthDownKey(id, 6));
|
||||
gQueue.push(new synthClick(id, new checker(0)));
|
||||
gQueue.push(new synthRightKey(id, new checker(1)));
|
||||
gQueue.push(new synthDownKey(id, new checker(6)));
|
||||
|
||||
gQueue.push(new synthClick("p1_in_div", 0, "p2_in_div", -1));
|
||||
gQueue.push(new synthClick("p1_in_div",
|
||||
new clickChecker(0, "p2_in_div", -1)));
|
||||
|
||||
gQueue.push(new synthTabTest("p", 0, true));
|
||||
gQueue.push(new synthTabTest("textarea", 12, true));
|
||||
gQueue.push(new synthTabTest("p", 0, false));
|
||||
gQueue.push(new synthShiftTab("p", new checker(0)));
|
||||
gQueue.push(new synthShiftTab("textarea", new checker(12)));
|
||||
gQueue.push(new synthTab("p", new checker(0)));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>Accessible focus testing</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/events.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
/**
|
||||
* Checker for invokers.
|
||||
*/
|
||||
function actionChecker(aDescription)
|
||||
{
|
||||
this.check = function actionChecker_check(aEvent)
|
||||
{
|
||||
var target = aEvent.accessible;
|
||||
is(target.description, aDescription,
|
||||
"Wrong description for " + prettyName(target));
|
||||
}
|
||||
}
|
||||
|
||||
var gFocusHandler = {
|
||||
handleEvent: function gFocusHandler_handleEvent(aEvent) {
|
||||
var elm = aEvent.target;
|
||||
if (elm.nodeType != nsIDOMNode.ELEMENT_NODE)
|
||||
return;
|
||||
|
||||
gTooltipElm.style.display = "block";
|
||||
|
||||
elm.setAttribute("aria-describedby", "tooltip");
|
||||
}
|
||||
};
|
||||
|
||||
var gBlurHandler = {
|
||||
handleEvent: function gBlurHandler_handleEvent(aEvent) {
|
||||
gTooltipElm.style.display = "none";
|
||||
|
||||
var elm = aEvent.target;
|
||||
if (elm.nodeType == nsIDOMNode.ELEMENT_NODE)
|
||||
elm.removeAttribute("aria-describedby");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Do tests.
|
||||
*/
|
||||
|
||||
// gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
var gButtonElm = null;
|
||||
var gTextboxElm = null;
|
||||
var gTooltipElm = null;
|
||||
|
||||
function doTests()
|
||||
{
|
||||
gButtonElm = getNode("button");
|
||||
gTextboxElm = getNode("textbox");
|
||||
gTooltipElm = getNode("tooltip");
|
||||
|
||||
gButtonElm.addEventListener("focus", gFocusHandler, false);
|
||||
gButtonElm.addEventListener("blur", gBlurHandler, false);
|
||||
gTextboxElm.addEventListener("focus", gFocusHandler, false);
|
||||
gTextboxElm.addEventListener("blur", gBlurHandler, false);
|
||||
|
||||
// The aria-describedby is changed on DOM focus. Accessible description
|
||||
// should be updated when a11y focus is fired.
|
||||
gQueue = new eventQueue(nsIAccessibleEvent.EVENT_FOCUS);
|
||||
gQueue.onFinish = function()
|
||||
{
|
||||
gButtonElm.removeEventListener("focus", gFocusHandler, false);
|
||||
gButtonElm.removeEventListener("blur", gBlurHandler, false);
|
||||
gTextboxElm.removeEventListener("focus", gFocusHandler, false);
|
||||
gTextboxElm.removeEventListener("blur", gBlurHandler, false);
|
||||
}
|
||||
|
||||
var checker = new actionChecker("It's a tooltip");
|
||||
gQueue.push(new synthFocus("button", checker));
|
||||
gQueue.push(new synthTab("textbox", checker));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTests);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=520709"
|
||||
title="mochitest to ensure name/description are updated on a11y focus if they were changed on DOM focus">
|
||||
Mozilla Bug 520709
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="tooltip" style="display: none" aria-hidden="true">It's a tooltip</div>
|
||||
<button id="button">button</button>
|
||||
<input id="textbox">
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -122,7 +122,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=391829
|
|||
|
||||
<div id="live" aria-live="polite">excuse <div id="liveChild">me</div></div>
|
||||
<div id="live2" role="marquee" aria-live="polite">excuse <div id="live2Child">me</div></div>
|
||||
<div id="live3" role="section">excuse</div>
|
||||
<div id="live3" role="region">excuse</div>
|
||||
<div id="log" role="log">excuse <div id="logChild">me</div></div>
|
||||
<div id="logAssertive" role="log" aria-live="assertive">excuse <div id="logAssertiveChild">me</div></div>
|
||||
<div id="marquee" role="marquee">excuse <div id="marqueeChild">me</div></div>
|
||||
|
|
|
@ -342,10 +342,6 @@ ifdef LIBXUL_SDK
|
|||
else
|
||||
rm -f $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
|
||||
rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
|
||||
endif
|
||||
ifndef MOZ_COCOA_PRINTING
|
||||
mkdir -p $(DIST)/$(APP_NAME).app/Contents/Plug-Ins
|
||||
rsync -a --copy-unsafe-links $(LIBXUL_DIST)/package/PrintPDE.plugin $(DIST)/$(APP_NAME).app/Contents/Plug-Ins
|
||||
endif
|
||||
-cp -L $(DIST)/bin/mangle $(DIST)/bin/shlibsign $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
|
||||
cp -RL $(DIST)/branding/firefox.icns $(DIST)/$(APP_NAME).app/Contents/Resources/firefox.icns
|
||||
|
|
|
@ -572,7 +572,7 @@ pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.
|
|||
pref("plugins.hide_infobar_for_missing_plugin", false);
|
||||
pref("plugins.hide_infobar_for_outdated_plugin", false);
|
||||
|
||||
pref("plugins.update.url", "https://www.mozilla.com/%LOCALE%/plugins/");
|
||||
pref("plugins.update.url", "https://www.mozilla.com/%LOCALE%/plugincheck/");
|
||||
pref("plugins.update.notifyUser", false);
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -903,3 +903,16 @@ pref("toolbar.customization.usesheet", false);
|
|||
|
||||
pref("dom.ipc.plugins.enabled", false);
|
||||
pref("dom.ipc.tabs.enabled", false);
|
||||
|
||||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
pref("browser.taskbar.previews.enable", true);
|
||||
pref("browser.taskbar.previews.max", 20);
|
||||
pref("browser.taskbar.previews.cachetime", 20);
|
||||
pref("browser.taskbar.lists.enabled", true);
|
||||
pref("browser.taskbar.lists.frequent.enabled", true);
|
||||
pref("browser.taskbar.lists.recent.enabled", false);
|
||||
pref("browser.taskbar.lists.maxListItemCount", 7);
|
||||
pref("browser.taskbar.lists.tasks.enabled", true);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
<command id="Browser:AddBookmarkAs"
|
||||
oncommand="PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksMenuFolderId);"/>
|
||||
<!-- The command is disabled for the hidden window. Otherwise its enabled
|
||||
state is handled by the BookmarkAllTabsHandler object. -->
|
||||
state is handled by gBookmarkAllTabsHandler. -->
|
||||
<command id="Browser:BookmarkAllTabs"
|
||||
oncommand="gBookmarkAllTabsHandler.doCommand();"
|
||||
disabled="true"/>
|
||||
|
|
|
@ -83,7 +83,8 @@ toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
|
|||
|
||||
%ifdef MOZ_WIDGET_GTK2
|
||||
/* Bookmarks override the "images-in-menus" metric in xul.css */
|
||||
.bookmark-item > .menu-iconic-left {
|
||||
.bookmark-item > .menu-iconic-left,
|
||||
.searchbar-engine-menuitem > .menu-iconic-left {
|
||||
visibility: inherit;
|
||||
}
|
||||
%endif
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
# Edward Lee <edward.lee@engineering.uiuc.edu>
|
||||
# Paul O’Shannessy <paul@oshannessy.com>
|
||||
# Nils Maier <maierman@web.de>
|
||||
# Rob Arnold <robarnold@cmu.edu>
|
||||
#
|
||||
# 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
|
||||
|
@ -73,15 +74,9 @@ var gLastBrowserCharset = null;
|
|||
var gPrevCharset = null;
|
||||
var gProxyFavIcon = null;
|
||||
var gLastValidURLStr = "";
|
||||
var gProgressCollapseTimer = null;
|
||||
var gInPrintPreviewMode = false;
|
||||
let gDownloadMgr = null;
|
||||
|
||||
// Global variable that holds the nsContextMenu instance.
|
||||
var gContextMenu = null;
|
||||
|
||||
var gAutoHideTabbarPrefListener = null;
|
||||
var gBookmarkAllTabsHandler = null;
|
||||
var gDownloadMgr = null;
|
||||
var gContextMenu = null; // nsContextMenu instance
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
var gEditUIVisible = true;
|
||||
|
@ -92,7 +87,6 @@ var gEditUIVisible = true;
|
|||
["gNavToolbox", "navigator-toolbox"],
|
||||
["gURLBar", "urlbar"],
|
||||
["gNavigatorBundle", "bundle_browser"],
|
||||
["gProgressMeterPanel", "statusbar-progresspanel"],
|
||||
["gFindBar", "FindToolbar"]
|
||||
].forEach(function (elementGlobal) {
|
||||
var [name, id] = elementGlobal;
|
||||
|
@ -135,6 +129,29 @@ let gInitialPages = [
|
|||
#include browser-places.js
|
||||
#include browser-tabPreviews.js
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
|
||||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
if (WINTASKBAR_CONTRACTID in Cc &&
|
||||
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
|
||||
let temp = {};
|
||||
Cu.import("resource://gre/modules/WindowsPreviewPerTab.jsm", temp);
|
||||
let AeroPeek = temp.AeroPeek;
|
||||
return {
|
||||
onOpenWindow: function () {
|
||||
AeroPeek.onOpenWindow(window);
|
||||
},
|
||||
onCloseWindow: function () {
|
||||
AeroPeek.onCloseWindow(window);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return null;
|
||||
});
|
||||
|
||||
/**
|
||||
* We can avoid adding multiple load event listeners and save some time by adding
|
||||
* one listener that calls all real handlers.
|
||||
|
@ -1077,7 +1094,6 @@ function prepareForStartup() {
|
|||
gBrowser.addEventListener("PluginOutdated", gMissingPluginInstaller.newMissingPlugin, true, true);
|
||||
gBrowser.addEventListener("PluginDisabled", gMissingPluginInstaller.newDisabledPlugin, true, true);
|
||||
gBrowser.addEventListener("NewPluginInstalled", gMissingPluginInstaller.refreshBrowser, false);
|
||||
gBrowser.addEventListener("NewTab", BrowserOpenTab, false);
|
||||
window.addEventListener("AppCommand", HandleAppCommandEvent, true);
|
||||
|
||||
var webNavigation;
|
||||
|
@ -1192,7 +1208,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
initializeSanitizer();
|
||||
|
||||
// Enable/Disable auto-hide tabbar
|
||||
gAutoHideTabbarPrefListener = new AutoHideTabbarPrefListener();
|
||||
gAutoHideTabbarPrefListener.toggleAutoHideTabbar();
|
||||
gPrefService.addObserver(gAutoHideTabbarPrefListener.domain,
|
||||
gAutoHideTabbarPrefListener, false);
|
||||
|
||||
|
@ -1279,7 +1295,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
}
|
||||
|
||||
// bookmark-all-tabs command
|
||||
gBookmarkAllTabsHandler = new BookmarkAllTabsHandler();
|
||||
gBookmarkAllTabsHandler.init();
|
||||
|
||||
// Attach a listener to watch for "command" events bubbling up from error
|
||||
// pages. This lets us fix bugs like 401575 which require error page UI to
|
||||
|
@ -1341,10 +1357,16 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
gBrowser.mPanelContainer.addEventListener("InstallBrowserTheme", LightWeightThemeWebInstaller, false, true);
|
||||
gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true);
|
||||
gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true);
|
||||
|
||||
if (Win7Features)
|
||||
Win7Features.onOpenWindow();
|
||||
}
|
||||
|
||||
function BrowserShutdown()
|
||||
{
|
||||
if (Win7Features)
|
||||
Win7Features.onCloseWindow();
|
||||
|
||||
gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
|
||||
gPrefService.removeObserver(allTabs.prefName, allTabs);
|
||||
tabPreviews.uninit();
|
||||
|
@ -1353,6 +1375,8 @@ function BrowserShutdown()
|
|||
|
||||
gGestureSupport.init(false);
|
||||
|
||||
FullScreen.cleanup();
|
||||
|
||||
try {
|
||||
FullZoom.destroy();
|
||||
}
|
||||
|
@ -1471,24 +1495,13 @@ function nonBrowserWindowShutdown()
|
|||
}
|
||||
#endif
|
||||
|
||||
function AutoHideTabbarPrefListener()
|
||||
{
|
||||
this.toggleAutoHideTabbar();
|
||||
}
|
||||
|
||||
AutoHideTabbarPrefListener.prototype =
|
||||
{
|
||||
var gAutoHideTabbarPrefListener = {
|
||||
domain: "browser.tabs.autoHide",
|
||||
observe: function (aSubject, aTopic, aPrefName)
|
||||
{
|
||||
if (aTopic != "nsPref:changed" || aPrefName != this.domain)
|
||||
return;
|
||||
|
||||
this.toggleAutoHideTabbar();
|
||||
observe: function (aSubject, aTopic, aPrefName) {
|
||||
if (aTopic == "nsPref:changed" && aPrefName == this.domain)
|
||||
this.toggleAutoHideTabbar();
|
||||
},
|
||||
|
||||
toggleAutoHideTabbar: function ()
|
||||
{
|
||||
toggleAutoHideTabbar: function () {
|
||||
if (gBrowser.tabContainer.childNodes.length == 1 &&
|
||||
window.toolbar.visible) {
|
||||
var aVisible = false;
|
||||
|
@ -1884,24 +1897,8 @@ function BrowserCloseTabOrWindow() {
|
|||
|
||||
function BrowserTryToCloseWindow()
|
||||
{
|
||||
if (WindowIsClosing()) {
|
||||
if (window.fullScreen) {
|
||||
gBrowser.mPanelContainer.removeEventListener("mousemove",
|
||||
FullScreen._collapseCallback, false);
|
||||
document.removeEventListener("keypress", FullScreen._keyToggleCallback, false);
|
||||
document.removeEventListener("popupshown", FullScreen._setPopupOpen, false);
|
||||
document.removeEventListener("popuphidden", FullScreen._setPopupOpen, false);
|
||||
gPrefService.removeObserver("browser.fullscreen", FullScreen);
|
||||
|
||||
var fullScrToggler = document.getElementById("fullscr-toggler");
|
||||
if (fullScrToggler) {
|
||||
fullScrToggler.removeEventListener("mouseover", FullScreen._expandCallback, false);
|
||||
fullScrToggler.removeEventListener("dragenter", FullScreen._expandCallback, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (WindowIsClosing())
|
||||
window.close(); // WindowIsClosing does all the necessary checks
|
||||
}
|
||||
}
|
||||
|
||||
function loadURI(uri, referrer, postData, allowThirdPartyFixup)
|
||||
|
@ -3489,11 +3486,11 @@ var FullScreen =
|
|||
this.showXULChrome("statusbar", window.fullScreen);
|
||||
document.getElementById("View:FullScreen").setAttribute("checked", !window.fullScreen);
|
||||
|
||||
var fullScrToggler = document.getElementById("fullscr-toggler");
|
||||
if (!window.fullScreen) {
|
||||
// Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
|
||||
// This will help simulate the "collapse" metaphor while also requiring less code and
|
||||
// events than raw listening of mouse coords.
|
||||
let fullScrToggler = document.getElementById("fullscr-toggler");
|
||||
if (!fullScrToggler) {
|
||||
fullScrToggler = document.createElement("toolbar");
|
||||
fullScrToggler.id = "fullscr-toggler";
|
||||
|
@ -3519,16 +3516,6 @@ var FullScreen =
|
|||
gPrefService.addObserver("browser.fullscreen", this, false);
|
||||
}
|
||||
else {
|
||||
document.removeEventListener("keypress", this._keyToggleCallback, false);
|
||||
document.removeEventListener("popupshown", this._setPopupOpen, false);
|
||||
document.removeEventListener("popuphidden", this._setPopupOpen, false);
|
||||
gPrefService.removeObserver("browser.fullscreen", this);
|
||||
|
||||
if (fullScrToggler) {
|
||||
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
|
||||
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
|
||||
}
|
||||
|
||||
// The user may quit fullscreen during an animation
|
||||
clearInterval(this._animationInterval);
|
||||
clearTimeout(this._animationTimeout);
|
||||
|
@ -3539,8 +3526,24 @@ var FullScreen =
|
|||
// This is needed if they use the context menu to quit fullscreen
|
||||
this._isPopupOpen = false;
|
||||
|
||||
this.cleanup();
|
||||
}
|
||||
},
|
||||
|
||||
cleanup: function () {
|
||||
if (window.fullScreen) {
|
||||
gBrowser.mPanelContainer.removeEventListener("mousemove",
|
||||
this._collapseCallback, false);
|
||||
document.removeEventListener("keypress", this._keyToggleCallback, false);
|
||||
document.removeEventListener("popupshown", this._setPopupOpen, false);
|
||||
document.removeEventListener("popuphidden", this._setPopupOpen, false);
|
||||
gPrefService.removeObserver("browser.fullscreen", this);
|
||||
|
||||
let fullScrToggler = document.getElementById("fullscr-toggler");
|
||||
if (fullScrToggler) {
|
||||
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
|
||||
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -3805,7 +3808,7 @@ var XULBrowserWindow = {
|
|||
lastURI: null,
|
||||
isBusy: false,
|
||||
|
||||
statusTimeoutInEffect: false,
|
||||
_progressCollapseTimer: 0,
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
||||
|
@ -3954,9 +3957,9 @@ var XULBrowserWindow = {
|
|||
|
||||
// Turn the status meter on.
|
||||
this.statusMeter.value = 0; // be sure to clear the progress bar
|
||||
if (gProgressCollapseTimer) {
|
||||
window.clearTimeout(gProgressCollapseTimer);
|
||||
gProgressCollapseTimer = null;
|
||||
if (this._progressCollapseTimer) {
|
||||
clearTimeout(this._progressCollapseTimer);
|
||||
this._progressCollapseTimer = 0;
|
||||
}
|
||||
else
|
||||
this.statusMeter.parentNode.collapsed = false;
|
||||
|
@ -4021,10 +4024,10 @@ var XULBrowserWindow = {
|
|||
this._busyUI = false;
|
||||
|
||||
// Turn the progress meter and throbber off.
|
||||
gProgressCollapseTimer = window.setTimeout(function () {
|
||||
gProgressMeterPanel.collapsed = true;
|
||||
gProgressCollapseTimer = null;
|
||||
}, 100);
|
||||
this._progressCollapseTimer = setTimeout(function (self) {
|
||||
self.statusMeter.parentNode.collapsed = true;
|
||||
self._progressCollapseTimer = 0;
|
||||
}, 100, this);
|
||||
|
||||
if (this.throbberElement)
|
||||
this.throbberElement.removeAttribute("busy");
|
||||
|
@ -4376,22 +4379,12 @@ var TabsProgressListener = {
|
|||
}
|
||||
}
|
||||
|
||||
function nsBrowserAccess()
|
||||
{
|
||||
}
|
||||
function nsBrowserAccess() { }
|
||||
|
||||
nsBrowserAccess.prototype =
|
||||
{
|
||||
QueryInterface : function(aIID)
|
||||
{
|
||||
if (aIID.equals(Ci.nsIBrowserDOMWindow) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
|
||||
|
||||
openURI : function(aURI, aOpener, aWhere, aContext)
|
||||
{
|
||||
openURI: function (aURI, aOpener, aWhere, aContext) {
|
||||
var newWindow = null;
|
||||
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
|
||||
|
@ -4462,8 +4455,7 @@ nsBrowserAccess.prototype =
|
|||
return newWindow;
|
||||
},
|
||||
|
||||
isTabContentWindow : function(aWindow)
|
||||
{
|
||||
isTabContentWindow: function (aWindow) {
|
||||
return gBrowser.browsers.some(function (browser) browser.contentWindow == aWindow);
|
||||
}
|
||||
}
|
||||
|
@ -5868,187 +5860,185 @@ function getPluginInfo(pluginElement)
|
|||
return {mimetype: tagMimetype, pluginsPage: pluginsPage};
|
||||
}
|
||||
|
||||
function missingPluginInstaller(){
|
||||
}
|
||||
var gMissingPluginInstaller = {
|
||||
|
||||
missingPluginInstaller.prototype.installSinglePlugin = function(aEvent){
|
||||
var missingPluginsArray = {};
|
||||
installSinglePlugin: function (aEvent) {
|
||||
var missingPluginsArray = {};
|
||||
|
||||
var pluginInfo = getPluginInfo(aEvent.target);
|
||||
missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
|
||||
var pluginInfo = getPluginInfo(aEvent.target);
|
||||
missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
|
||||
|
||||
if (missingPluginsArray) {
|
||||
window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
}
|
||||
|
||||
aEvent.stopPropagation();
|
||||
}
|
||||
|
||||
missingPluginInstaller.prototype.managePlugins = function(aEvent){
|
||||
BrowserOpenAddonsMgr("plugins");
|
||||
aEvent.stopPropagation();
|
||||
}
|
||||
|
||||
missingPluginInstaller.prototype.newMissingPlugin = function(aEvent){
|
||||
// Since we are expecting also untrusted events, make sure
|
||||
// that the target is a plugin
|
||||
if (!(aEvent.target instanceof Components.interfaces.nsIObjectLoadingContent))
|
||||
return;
|
||||
|
||||
// For broken non-object plugin tags, register a click handler so
|
||||
// that the user can click the plugin replacement to get the new
|
||||
// plugin. Object tags can, and often do, deal with that themselves,
|
||||
// so don't stomp on the page developers toes.
|
||||
|
||||
if (aEvent.type != "PluginBlocklisted" &&
|
||||
aEvent.type != "PluginOutdated" &&
|
||||
!(aEvent.target instanceof HTMLObjectElement)) {
|
||||
aEvent.target.addEventListener("click",
|
||||
gMissingPluginInstaller.installSinglePlugin,
|
||||
true);
|
||||
}
|
||||
|
||||
let hideBarPrefName = aEvent.type == "PluginOutdated" ?
|
||||
"plugins.hide_infobar_for_outdated_plugin" :
|
||||
"plugins.hide_infobar_for_missing_plugin";
|
||||
if (gPrefService.getBoolPref(hideBarPrefName))
|
||||
return;
|
||||
|
||||
var browser = gBrowser.getBrowserForDocument(aEvent.target.ownerDocument
|
||||
.defaultView.top.document);
|
||||
if (!browser.missingPlugins)
|
||||
browser.missingPlugins = {};
|
||||
|
||||
var pluginInfo = getPluginInfo(aEvent.target);
|
||||
|
||||
browser.missingPlugins[pluginInfo.mimetype] = pluginInfo;
|
||||
|
||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||
|
||||
// Should only display one of these warnings per page.
|
||||
// In order of priority, they are: outdated > missing > blocklisted
|
||||
|
||||
// If there is already an outdated plugin notification then do nothing
|
||||
if (notificationBox.getNotificationWithValue("outdated-plugins"))
|
||||
return;
|
||||
var blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
|
||||
var missingNotification = notificationBox.getNotificationWithValue("missing-plugins");
|
||||
var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
||||
|
||||
function showBlocklistInfo() {
|
||||
var url = formatURL("extensions.blocklist.detailsURL", true);
|
||||
gBrowser.loadOneTab(url, {inBackground: false});
|
||||
return true;
|
||||
}
|
||||
|
||||
function showOutdatedPluginsInfo() {
|
||||
var url = formatURL("plugins.update.url", true);
|
||||
gBrowser.loadOneTab(url, {inBackground: false});
|
||||
return true;
|
||||
}
|
||||
|
||||
function showPluginsMissing() {
|
||||
// get the urls of missing plugins
|
||||
var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
|
||||
if (missingPluginsArray) {
|
||||
window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
}
|
||||
}
|
||||
|
||||
if (aEvent.type == "PluginBlocklisted") {
|
||||
if (blockedNotification || missingNotification)
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
|
||||
managePlugins: function (aEvent) {
|
||||
BrowserOpenAddonsMgr("plugins");
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
|
||||
newMissingPlugin: function (aEvent) {
|
||||
// Since we are expecting also untrusted events, make sure
|
||||
// that the target is a plugin
|
||||
if (!(aEvent.target instanceof Ci.nsIObjectLoadingContent))
|
||||
return;
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginBlocked-16.png";
|
||||
let messageString = gNavigatorBundle.getString("blockedpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showBlocklistInfo
|
||||
}, {
|
||||
label: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showOutdatedPluginsInfo
|
||||
}];
|
||||
// For broken non-object plugin tags, register a click handler so
|
||||
// that the user can click the plugin replacement to get the new
|
||||
// plugin. Object tags can, and often do, deal with that themselves,
|
||||
// so don't stomp on the page developers toes.
|
||||
|
||||
notificationBox.appendNotification(messageString, "blocked-plugins",
|
||||
iconURL, priority, buttons);
|
||||
}
|
||||
else if (aEvent.type == "PluginOutdated") {
|
||||
// Cancel any notification about blocklisting/missing plugins
|
||||
if (blockedNotification)
|
||||
blockedNotification.close();
|
||||
if (missingNotification)
|
||||
missingNotification.close();
|
||||
if (aEvent.type != "PluginBlocklisted" &&
|
||||
aEvent.type != "PluginOutdated" &&
|
||||
!(aEvent.target instanceof HTMLObjectElement)) {
|
||||
aEvent.target.addEventListener("click",
|
||||
gMissingPluginInstaller.installSinglePlugin,
|
||||
true);
|
||||
}
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginOutdated-16.png";
|
||||
let messageString = gNavigatorBundle.getString("outdatedpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showOutdatedPluginsInfo
|
||||
}];
|
||||
|
||||
notificationBox.appendNotification(messageString, "outdated-plugins",
|
||||
iconURL, priority, buttons);
|
||||
}
|
||||
else if (aEvent.type == "PluginNotFound") {
|
||||
if (missingNotification)
|
||||
let hideBarPrefName = aEvent.type == "PluginOutdated" ?
|
||||
"plugins.hide_infobar_for_outdated_plugin" :
|
||||
"plugins.hide_infobar_for_missing_plugin";
|
||||
if (gPrefService.getBoolPref(hideBarPrefName))
|
||||
return;
|
||||
|
||||
// Cancel any notification about blocklisting plugins
|
||||
if (blockedNotification)
|
||||
blockedNotification.close();
|
||||
var browser = gBrowser.getBrowserForDocument(aEvent.target.ownerDocument
|
||||
.defaultView.top.document);
|
||||
if (!browser.missingPlugins)
|
||||
browser.missingPlugins = {};
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
|
||||
let messageString = gNavigatorBundle.getString("missingpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("missingpluginsMessage.button.label"),
|
||||
accessKey: gNavigatorBundle.getString("missingpluginsMessage.button.accesskey"),
|
||||
popup: null,
|
||||
callback: showPluginsMissing
|
||||
}];
|
||||
|
||||
notificationBox.appendNotification(messageString, "missing-plugins",
|
||||
iconURL, priority, buttons);
|
||||
var pluginInfo = getPluginInfo(aEvent.target);
|
||||
|
||||
browser.missingPlugins[pluginInfo.mimetype] = pluginInfo;
|
||||
|
||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||
|
||||
// Should only display one of these warnings per page.
|
||||
// In order of priority, they are: outdated > missing > blocklisted
|
||||
|
||||
// If there is already an outdated plugin notification then do nothing
|
||||
if (notificationBox.getNotificationWithValue("outdated-plugins"))
|
||||
return;
|
||||
var blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
|
||||
var missingNotification = notificationBox.getNotificationWithValue("missing-plugins");
|
||||
var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
||||
|
||||
function showBlocklistInfo() {
|
||||
var url = formatURL("extensions.blocklist.detailsURL", true);
|
||||
gBrowser.loadOneTab(url, {inBackground: false});
|
||||
return true;
|
||||
}
|
||||
|
||||
function showOutdatedPluginsInfo() {
|
||||
var url = formatURL("plugins.update.url", true);
|
||||
gBrowser.loadOneTab(url, {inBackground: false});
|
||||
return true;
|
||||
}
|
||||
|
||||
function showPluginsMissing() {
|
||||
// get the urls of missing plugins
|
||||
var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
|
||||
if (missingPluginsArray) {
|
||||
openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
|
||||
"PFSWindow", "chrome,centerscreen,resizable=yes",
|
||||
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
|
||||
}
|
||||
}
|
||||
|
||||
if (aEvent.type == "PluginBlocklisted") {
|
||||
if (blockedNotification || missingNotification)
|
||||
return;
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginBlocked-16.png";
|
||||
let messageString = gNavigatorBundle.getString("blockedpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showBlocklistInfo
|
||||
}, {
|
||||
label: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showOutdatedPluginsInfo
|
||||
}];
|
||||
|
||||
notificationBox.appendNotification(messageString, "blocked-plugins",
|
||||
iconURL, priority, buttons);
|
||||
}
|
||||
else if (aEvent.type == "PluginOutdated") {
|
||||
// Cancel any notification about blocklisting/missing plugins
|
||||
if (blockedNotification)
|
||||
blockedNotification.close();
|
||||
if (missingNotification)
|
||||
missingNotification.close();
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginOutdated-16.png";
|
||||
let messageString = gNavigatorBundle.getString("outdatedpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
|
||||
popup: null,
|
||||
callback: showOutdatedPluginsInfo
|
||||
}];
|
||||
|
||||
notificationBox.appendNotification(messageString, "outdated-plugins",
|
||||
iconURL, priority, buttons);
|
||||
}
|
||||
else if (aEvent.type == "PluginNotFound") {
|
||||
if (missingNotification)
|
||||
return;
|
||||
|
||||
// Cancel any notification about blocklisting plugins
|
||||
if (blockedNotification)
|
||||
blockedNotification.close();
|
||||
|
||||
let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
|
||||
let messageString = gNavigatorBundle.getString("missingpluginsMessage.title");
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.getString("missingpluginsMessage.button.label"),
|
||||
accessKey: gNavigatorBundle.getString("missingpluginsMessage.button.accesskey"),
|
||||
popup: null,
|
||||
callback: showPluginsMissing
|
||||
}];
|
||||
|
||||
notificationBox.appendNotification(messageString, "missing-plugins",
|
||||
iconURL, priority, buttons);
|
||||
}
|
||||
},
|
||||
|
||||
newDisabledPlugin: function (aEvent) {
|
||||
// Since we are expecting also untrusted events, make sure
|
||||
// that the target is a plugin
|
||||
if (!(aEvent.target instanceof Ci.nsIObjectLoadingContent))
|
||||
return;
|
||||
|
||||
aEvent.target.addEventListener("click",
|
||||
gMissingPluginInstaller.managePlugins,
|
||||
true);
|
||||
},
|
||||
|
||||
refreshBrowser: function (aEvent) {
|
||||
// browser elements are anonymous so we can't just use target.
|
||||
var browser = aEvent.originalTarget;
|
||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||
var notification = notificationBox.getNotificationWithValue("missing-plugins");
|
||||
|
||||
// clear the plugin list, now that at least one plugin has been installed
|
||||
browser.missingPlugins = null;
|
||||
if (notification) {
|
||||
// reset UI
|
||||
notificationBox.removeNotification(notification);
|
||||
}
|
||||
// reload the browser to make the new plugin show.
|
||||
browser.reload();
|
||||
}
|
||||
}
|
||||
|
||||
missingPluginInstaller.prototype.newDisabledPlugin = function(aEvent){
|
||||
// Since we are expecting also untrusted events, make sure
|
||||
// that the target is a plugin
|
||||
if (!(aEvent.target instanceof Components.interfaces.nsIObjectLoadingContent))
|
||||
return;
|
||||
|
||||
aEvent.target.addEventListener("click",
|
||||
gMissingPluginInstaller.managePlugins,
|
||||
true);
|
||||
}
|
||||
|
||||
missingPluginInstaller.prototype.refreshBrowser = function(aEvent) {
|
||||
// browser elements are anonymous so we can't just use target.
|
||||
var browser = aEvent.originalTarget;
|
||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||
var notification = notificationBox.getNotificationWithValue("missing-plugins");
|
||||
|
||||
// clear the plugin list, now that at least one plugin has been installed
|
||||
browser.missingPlugins = null;
|
||||
if (notification) {
|
||||
// reset UI
|
||||
notificationBox.removeNotification(notification);
|
||||
}
|
||||
// reload the browser to make the new plugin show.
|
||||
browser.reload();
|
||||
}
|
||||
|
||||
var gMissingPluginInstaller = new missingPluginInstaller();
|
||||
};
|
||||
|
||||
function convertFromUnicode(charset, str)
|
||||
{
|
||||
|
@ -6298,20 +6288,12 @@ function formatURL(aFormat, aIsPref) {
|
|||
* This also takes care of updating the command enabled-state when tabs are
|
||||
* created or removed.
|
||||
*/
|
||||
function BookmarkAllTabsHandler() {
|
||||
this._command = document.getElementById("Browser:BookmarkAllTabs");
|
||||
gBrowser.addEventListener("TabOpen", this, true);
|
||||
gBrowser.addEventListener("TabClose", this, true);
|
||||
this._updateCommandState();
|
||||
}
|
||||
|
||||
BookmarkAllTabsHandler.prototype = {
|
||||
QueryInterface: function BATH_QueryInterface(aIID) {
|
||||
if (aIID.equals(Ci.nsIDOMEventListener) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_NOINTERFACE;
|
||||
var gBookmarkAllTabsHandler = {
|
||||
init: function () {
|
||||
this._command = document.getElementById("Browser:BookmarkAllTabs");
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", this, true);
|
||||
gBrowser.tabContainer.addEventListener("TabClose", this, true);
|
||||
this._updateCommandState();
|
||||
},
|
||||
|
||||
_updateCommandState: function BATH__updateCommandState(aTabClose) {
|
||||
|
@ -7079,7 +7061,7 @@ var LightWeightThemeWebInstaller = {
|
|||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "InstallBrowserTheme":
|
||||
this._install(event);
|
||||
this._installRequest(event);
|
||||
break;
|
||||
case "PreviewBrowserTheme":
|
||||
this._preview(event);
|
||||
|
@ -7097,14 +7079,14 @@ var LightWeightThemeWebInstaller = {
|
|||
return this._manager = temp.LightweightThemeManager;
|
||||
},
|
||||
|
||||
_install: function (event) {
|
||||
_installRequest: function (event) {
|
||||
var node = event.target;
|
||||
var data = this._getThemeFromNode(node);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (this._isAllowed(node)) {
|
||||
this._manager.currentTheme = data;
|
||||
this._install(data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7119,15 +7101,66 @@ var LightWeightThemeWebInstaller = {
|
|||
label: allowButtonText,
|
||||
accessKey: allowButtonAccesskey,
|
||||
callback: function () {
|
||||
LightWeightThemeWebInstaller._manager.currentTheme = data;
|
||||
LightWeightThemeWebInstaller._install(data);
|
||||
}
|
||||
}];
|
||||
|
||||
this._removePreviousNotifications();
|
||||
|
||||
var notificationBox = gBrowser.getNotificationBox();
|
||||
notificationBox.appendNotification(message, "lwtheme-install-request", "",
|
||||
notificationBox.PRIORITY_INFO_MEDIUM,
|
||||
buttons);
|
||||
},
|
||||
|
||||
_install: function (newTheme) {
|
||||
var previousTheme = this._manager.currentTheme;
|
||||
this._manager.currentTheme = newTheme;
|
||||
if (this._manager.currentTheme &&
|
||||
this._manager.currentTheme.id == newTheme.id)
|
||||
this._postInstallNotification(newTheme, previousTheme);
|
||||
},
|
||||
|
||||
_postInstallNotification: function (newTheme, previousTheme) {
|
||||
function text(id) {
|
||||
return gNavigatorBundle.getString("lwthemePostInstallNotification." + id);
|
||||
}
|
||||
|
||||
var buttons = [{
|
||||
label: text("undoButton"),
|
||||
accessKey: text("undoButton.accesskey"),
|
||||
callback: function () {
|
||||
LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id);
|
||||
LightWeightThemeWebInstaller._manager.currentTheme = previousTheme;
|
||||
}
|
||||
}, {
|
||||
label: text("manageButton"),
|
||||
accessKey: text("manageButton.accesskey"),
|
||||
callback: function () {
|
||||
BrowserOpenAddonsMgr("themes");
|
||||
}
|
||||
}];
|
||||
|
||||
this._removePreviousNotifications();
|
||||
|
||||
var notificationBox = gBrowser.getNotificationBox();
|
||||
notificationBox.appendNotification(text("message"),
|
||||
"lwtheme-install-notification", "",
|
||||
notificationBox.PRIORITY_INFO_MEDIUM,
|
||||
buttons);
|
||||
},
|
||||
|
||||
_removePreviousNotifications: function () {
|
||||
var box = gBrowser.getNotificationBox();
|
||||
|
||||
["lwtheme-install-request",
|
||||
"lwtheme-install-notification"].forEach(function (value) {
|
||||
var notification = box.getNotificationWithValue(value);
|
||||
if (notification)
|
||||
box.removeNotification(notification);
|
||||
});
|
||||
},
|
||||
|
||||
_preview: function (event) {
|
||||
if (!this._isAllowed(event.target))
|
||||
return;
|
||||
|
|
|
@ -577,7 +577,6 @@
|
|||
<tabbrowser id="content" disablehistory="true"
|
||||
flex="1" contenttooltip="aHTMLTooltip"
|
||||
contentcontextmenu="contentAreaContextMenu"
|
||||
onnewtab="BrowserOpenTab();"
|
||||
autocompletepopup="PopupAutoComplete"
|
||||
ondrop="contentAreaDNDObserver.onDrop(event)"
|
||||
onclick="return contentAreaClick(event, false);"/>
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
- Mark Pilgrim <pilgrim@gmail.com>
|
||||
- Dão Gottwald <dao@mozilla.com>
|
||||
- Paul O’Shannessy <paul@oshannessy.com>
|
||||
- Rob Arnold <tellrob@gmail.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
|
||||
|
@ -82,7 +83,7 @@
|
|||
<xul:tooltip onpopupshowing="return this.parentNode.parentNode.parentNode.createTooltip(event);"/>
|
||||
<xul:menupopup anonid="tabContextMenu" onpopupshowing="this.parentNode.parentNode.parentNode.updatePopupMenu(this);">
|
||||
<xul:menuitem id="context_newTab" label="&newTab.label;" accesskey="&newTab.accesskey;"
|
||||
xbl:inherits="oncommand=onnewtab"/>
|
||||
command="cmd_newNavigatorTab"/>
|
||||
<xul:menuseparator/>
|
||||
<xul:menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
|
||||
oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
|
||||
|
@ -126,7 +127,6 @@
|
|||
anonid="tabcontainer"
|
||||
setfocus="false"
|
||||
onclick="this.parentNode.parentNode.parentNode.onTabClick(event);"
|
||||
xbl:inherits="onnewtab"
|
||||
ondblclick="this.parentNode.parentNode.parentNode.onTabBarDblClick(event);"
|
||||
onclosetab="var node = this.parentNode;
|
||||
while (node.localName != 'tabbrowser')
|
||||
|
@ -236,6 +236,29 @@
|
|||
null
|
||||
</field>
|
||||
|
||||
<field name="_previewMode">
|
||||
false
|
||||
</field>
|
||||
|
||||
<method name="previewTab">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aCallback"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let currentTab = this.selectedTab;
|
||||
try {
|
||||
// Suppress focus, ownership and selected tab changes
|
||||
this._previewMode = true;
|
||||
this.selectedTab = aTab;
|
||||
aCallback();
|
||||
} finally {
|
||||
this.selectedTab = currentTab;
|
||||
this._previewMode = false;
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="getBrowserAtIndex">
|
||||
<parameter name="aIndex"/>
|
||||
<body>
|
||||
|
@ -843,7 +866,8 @@
|
|||
if (this.mCurrentBrowser == newBrowser && !aForceUpdate)
|
||||
return;
|
||||
|
||||
if (this.mCurrentTab != this.selectedTab)
|
||||
// Preview mode should not reset the owner
|
||||
if (!this._previewMode && this.mCurrentTab != this.selectedTab)
|
||||
this.mCurrentTab.owner = null;
|
||||
|
||||
this._lastRelatedTab = null;
|
||||
|
@ -897,7 +921,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
|
||||
// Don't switch the fast find - this tab switch is temporary
|
||||
if (!this._previewMode)
|
||||
this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
|
||||
|
||||
// Update the window title.
|
||||
this.updateTitlebar();
|
||||
|
@ -935,18 +961,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
// We've selected the new tab, so go ahead and notify listeners.
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("TabSelect", true, false);
|
||||
this.mCurrentTab.dispatchEvent(event);
|
||||
// TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
|
||||
// that might rely upon the other changes suppressed.
|
||||
// Focus is suppressed in the event that the main browser window is minimized - focusing a tab would restore the window
|
||||
if (!this._previewMode) {
|
||||
// We've selected the new tab, so go ahead and notify listeners.
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("TabSelect", true, false);
|
||||
this.mCurrentTab.dispatchEvent(event);
|
||||
|
||||
// change focus to the new tab if nothing is focused, the old tab
|
||||
// is focused or there is something in the new tab to focus. One
|
||||
// specific case where focus is not changed is when the new tab
|
||||
// has no focused element and a chrome element is focused.
|
||||
if (!focusedChromeElement || focusedChromeElement == oldBrowser ||
|
||||
fm.getFocusedElementForWindow(window.content, true, {}))
|
||||
fm.setFocus(newBrowser, fm.FLAG_NOSCROLL);
|
||||
// change focus to the new tab if nothing is focused, the old tab
|
||||
// is focused or there is something in the new tab to focus. One
|
||||
// specific case where focus is not changed is when the new tab
|
||||
// has no focused element and a chrome element is focused.
|
||||
if ((!focusedChromeElement || focusedChromeElement == oldBrowser ||
|
||||
fm.getFocusedElementForWindow(window.content, true, {})))
|
||||
fm.setFocus(newBrowser, fm.FLAG_NOSCROLL);
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -1314,30 +1345,6 @@
|
|||
if (t.previousSibling.selected)
|
||||
t.setAttribute("afterselected", true);
|
||||
|
||||
if (!blank) {
|
||||
// Stop the existing about:blank load. Otherwise, if aURI
|
||||
// doesn't stop in-progress loads on its own, we'll get into
|
||||
// trouble with multiple parallel loads running at once.
|
||||
b.stop();
|
||||
|
||||
// pretend the user typed this so it'll be available till
|
||||
// the document successfully loads
|
||||
b.userTypedValue = aURI;
|
||||
|
||||
if (aPostData === undefined)
|
||||
aPostData = null;
|
||||
const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
|
||||
var flags = nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
if (aAllowThirdPartyFixup) {
|
||||
flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
}
|
||||
try {
|
||||
b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
|
||||
}
|
||||
catch (ex) {
|
||||
}
|
||||
}
|
||||
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
// Do this asynchronically, as we don't know yet if the tab
|
||||
|
@ -1361,6 +1368,25 @@
|
|||
evt.initEvent("TabOpen", true, false);
|
||||
t.dispatchEvent(evt);
|
||||
|
||||
if (!blank) {
|
||||
// Stop the existing about:blank load. Otherwise, if aURI
|
||||
// doesn't stop in-progress loads on its own, we'll get into
|
||||
// trouble with multiple parallel loads running at once.
|
||||
b.stop();
|
||||
|
||||
// pretend the user typed this so it'll be available till
|
||||
// the document successfully loads
|
||||
b.userTypedValue = aURI;
|
||||
|
||||
let flags = aAllowThirdPartyFixup ?
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP :
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
try {
|
||||
b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
|
||||
}
|
||||
catch (ex) { }
|
||||
}
|
||||
|
||||
// Check if we're opening a tab related to the current tab and
|
||||
// move it to after the current tab.
|
||||
// aReferrerURI is null or undefined if the tab is opened from
|
||||
|
@ -1769,12 +1795,8 @@
|
|||
<![CDATA[
|
||||
// See hack note in the tabbrowser-close-button binding
|
||||
if (!this._blockDblClick && aEvent.button == 0 &&
|
||||
aEvent.originalTarget.localName == "box") {
|
||||
// xxx this needs to check that we're in the empty area of the tabstrip
|
||||
var e = document.createEvent("Events");
|
||||
e.initEvent("NewTab", true, true);
|
||||
this.dispatchEvent(e);
|
||||
}
|
||||
aEvent.originalTarget.localName == "box")
|
||||
BrowserOpenTab();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
|
|
@ -99,6 +99,7 @@ _BROWSER_FILES = \
|
|||
browser_bug481560.js \
|
||||
browser_bug477014.js \
|
||||
browser_bug495058.js \
|
||||
browser_bug521216.js \
|
||||
browser_discovery.js \
|
||||
browser_tabfocus.js \
|
||||
discovery.html \
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
var expected = ["TabOpen", "onLinkIconAvailable", "onLocationChange", "onStateChange"];
|
||||
var actual = [];
|
||||
var tabIndex = -1;
|
||||
__defineGetter__("tab", function () gBrowser.tabContainer.childNodes[tabIndex]);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
tabIndex = gBrowser.tabContainer.childElementCount;
|
||||
gBrowser.addTabsProgressListener(progressListener);
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", TabOpen, false);
|
||||
gBrowser.addTab("http://example.org/browser/browser/base/content/test/dummy_page.html");
|
||||
}
|
||||
|
||||
function record(aName) {
|
||||
info("got " + aName);
|
||||
if (actual.indexOf(aName) == -1)
|
||||
actual.push(aName);
|
||||
if (actual.length == expected.length) {
|
||||
is(actual.toString(), expected.toString(),
|
||||
"got events and progress notifications in expected order");
|
||||
gBrowser.removeTab(tab);
|
||||
gBrowser.removeTabsProgressListener(progressListener);
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", TabOpen, false);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function TabOpen(aEvent) {
|
||||
if (aEvent.target == tab)
|
||||
record(arguments.callee.name);
|
||||
}
|
||||
|
||||
var progressListener = {
|
||||
onLocationChange: function onLocationChange(aBrowser) {
|
||||
if (aBrowser == tab.linkedBrowser)
|
||||
record(arguments.callee.name);
|
||||
},
|
||||
onProgressChange: function () {},
|
||||
onSecurityChange: function () {},
|
||||
onStateChange: function onStateChange(aBrowser) {
|
||||
if (aBrowser == tab.linkedBrowser)
|
||||
record(arguments.callee.name);
|
||||
},
|
||||
onStatusChange: function () {},
|
||||
onLinkIconAvailable: function onLinkIconAvailable(aBrowser) {
|
||||
if (aBrowser == tab.linkedBrowser)
|
||||
record(arguments.callee.name);
|
||||
}
|
||||
};
|
|
@ -76,6 +76,12 @@ ifndef WINCE
|
|||
DIRS += migration
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
ifndef WINCE
|
||||
DIRS += wintaskbar
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MOZ_SAFE_BROWSING
|
||||
DIRS += safebrowsing
|
||||
endif
|
||||
|
|
|
@ -505,7 +505,7 @@ var nsBrowserContentHandler = {
|
|||
#endif
|
||||
},
|
||||
|
||||
helpInfo : " -browser Open a browser window.\n",
|
||||
helpInfo : " -browser Open a browser window.\n",
|
||||
|
||||
/* nsIBrowserHandler */
|
||||
|
||||
|
|
|
@ -354,6 +354,19 @@ BrowserGlue.prototype = {
|
|||
// been warned about them yet, open the plugins update page.
|
||||
if (this._prefs.getBoolPref(PREF_PLUGINS_NOTIFYUSER))
|
||||
this._showPluginUpdatePage();
|
||||
|
||||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
// For windows seven, initialize the jump list module.
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
if (WINTASKBAR_CONTRACTID in Cc &&
|
||||
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
|
||||
let temp = {};
|
||||
Cu.import("resource://gre/modules/WindowsJumpLists.jsm", temp);
|
||||
temp.WinTaskbarJumpList.startup();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
|
||||
_onQuitRequest: function(aCancelQuit, aQuitType)
|
||||
|
@ -645,7 +658,7 @@ BrowserGlue.prototype = {
|
|||
var bookmarksBackupFile = PlacesUtils.backups.getMostRecent("json");
|
||||
if (bookmarksBackupFile) {
|
||||
// restore from JSON backup
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(bookmarksBackupFile);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(bookmarksBackupFile);
|
||||
importBookmarks = false;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
|
||||
%ifdef PLACES_QUERY_BUILDER
|
||||
.history-calendar {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#calendar");
|
||||
}
|
||||
|
||||
button.commandButton {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#command-button");
|
||||
}
|
||||
|
||||
.filterList {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#filter-button");
|
||||
}
|
||||
%endif
|
||||
|
||||
#contentTitle {
|
||||
width: 0px;
|
||||
|
|
|
@ -511,7 +511,7 @@ var PlacesOrganizer = {
|
|||
return;
|
||||
|
||||
try {
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(aFile);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(aFile);
|
||||
}
|
||||
catch(ex) {
|
||||
this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
|
||||
|
|
|
@ -3,38 +3,7 @@
|
|||
<bindings id="placesBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="command-button" extends="chrome://global/content/bindings/button.xml#button">
|
||||
<implementation>
|
||||
<method name="updateActiveView">
|
||||
<body><![CDATA[
|
||||
if (this.hasAttribute("view"))
|
||||
PlacesController.activeView = document.getElementById(this.getAttribute("view"));
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="click" button="0" action="this.updateActiveView();"/>
|
||||
<handler event="keypress" keycode="VK_SPACE" action="this.updateActiveView();"/>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="filter-button" extends="chrome://global/content/bindings/button.xml#menu">
|
||||
<content>
|
||||
<xul:stack flex="1" class="box-inherit button-box">
|
||||
<xul:image class="button-icon" xbl:inherits="src=image"/>
|
||||
<xul:dropmarker class="button-menu-dropmarker" xbl:inherits="open,disabled"/>
|
||||
</xul:stack>
|
||||
<children includes="menupopup"/>
|
||||
</content>
|
||||
<handlers>
|
||||
<handler event="command"><![CDATA[
|
||||
PlacesSearchBox.filterCollection = event.target.getAttribute("value");
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
#ifdef PLACES_QUERY_BUILDER
|
||||
<binding id="calendar">
|
||||
|
|
|
@ -1311,7 +1311,7 @@ var PlacesUIUtils = {
|
|||
if (this.__lookupGetter__("leftPaneFolderId")) {
|
||||
try {
|
||||
queryName = PlacesUtils.annotations.
|
||||
getItemAnnotation(itemId, ORGANIZER_QUERY_ANNO);
|
||||
getItemAnnotation(aItemId, ORGANIZER_QUERY_ANNO);
|
||||
}
|
||||
catch (ex) {
|
||||
// doesn't have the annotation
|
||||
|
|
|
@ -6,7 +6,7 @@ browser.jar:
|
|||
* content/browser/places/places.js (content/places.js)
|
||||
* content/browser/places/places.xml (content/places.xml)
|
||||
content/browser/places/places.css (content/places.css)
|
||||
content/browser/places/organizer.css (content/organizer.css)
|
||||
* content/browser/places/organizer.css (content/organizer.css)
|
||||
* content/browser/places/bookmarkProperties.xul (content/bookmarkProperties.xul)
|
||||
* content/browser/places/bookmarkProperties.js (content/bookmarkProperties.js)
|
||||
* content/browser/places/placesOverlay.xul (content/placesOverlay.xul)
|
||||
|
|
|
@ -48,6 +48,7 @@ _CHROME_TEST_FILES = \
|
|||
test_bug485100-change-case-loses-tag.xul \
|
||||
test_bug427633_no_newfolder_if_noip.xul \
|
||||
test_multiple_left_pane.xul \
|
||||
test_bug510634.xul \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_CHROME_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.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 Places test code.
|
||||
-
|
||||
- The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Asaf Romano (Original Author)
|
||||
-
|
||||
- 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 ***** -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="510634: Wrong icons on bookmarks sidebar"
|
||||
onload="runTest();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" />
|
||||
|
||||
<tree id="tree"
|
||||
type="places"
|
||||
flex="1">
|
||||
<treecols>
|
||||
<treecol label="Title" id="title" anonid="title" primary="true" ordinal="1" flex="1"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/**
|
||||
* Bug 510634 - Wrong icons on bookmarks sidebar
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=510634
|
||||
*
|
||||
* Ensures that properties for special queries are set on their tree nodes,
|
||||
* even if PlacesUIUtils.leftPaneFolderId was not initialized.
|
||||
*/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createSupportsArray() {
|
||||
return Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
}
|
||||
|
||||
// converts nsISupportsArray of atoms to a simple JS-strings array
|
||||
function convertPropertiesToJSArray(aSupportsArray) {
|
||||
var results = [];
|
||||
var count = aSupportsArray.Count();
|
||||
for (var i = 0; i < count; i++)
|
||||
results.push(aSupportsArray.QueryElementAt(i, Ci.nsIAtom).toString());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
// We need to cache and restore this getter in order to simulate
|
||||
// Bug 510634
|
||||
let cachedLeftPaneFolderIdGetter =
|
||||
PlacesUIUtils.__lookupGetter__("leftPaneFolderId");
|
||||
|
||||
let leftPaneFolderId = PlacesUIUtils.leftPaneFolderId;
|
||||
|
||||
// restore the getter
|
||||
PlacesUIUtils.__defineGetter__("leftPaneFolderId", cachedLeftPaneFolderIdGetter);
|
||||
|
||||
// Setup the places tree contents.
|
||||
let tree = document.getElementById("tree");
|
||||
tree.place = "place:queryType=1&folder=" + leftPaneFolderId;
|
||||
|
||||
// Open All Bookmarks
|
||||
asContainer(tree.view.nodeForTreeIndex(2)).containerOpen = true;
|
||||
|
||||
// The query-property is set on the title column for each row.
|
||||
let titleColumn = tree.treeBoxObject.columns.getColumnAt(0);
|
||||
|
||||
["History", "Tags", "AllBookmarks", "BookmarksToolbar",
|
||||
"BookmarksMenu", "UnfiledBookmarks"].forEach(
|
||||
function(aQueryName, aRow) {
|
||||
let rowProperties = createSupportsArray();
|
||||
tree.view.getCellProperties(aRow, titleColumn, rowProperties);
|
||||
rowProperties = convertPropertiesToJSArray(rowProperties);
|
||||
ok(rowProperties.indexOf("OrganizerQuery_" + aQueryName) != -1,
|
||||
"OrganizerQuery_" + aQueryName + " is set");
|
||||
}
|
||||
);
|
||||
|
||||
// Close the root node
|
||||
tree.getResult().root.containerOpen = false;
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -103,7 +103,7 @@ function run_test() {
|
|||
} catch(ex) { do_throw("couldn't export to file: " + ex); }
|
||||
LOG("exported json");
|
||||
try {
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile);
|
||||
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
|
||||
LOG("imported json");
|
||||
validate();
|
||||
|
|
|
@ -83,7 +83,7 @@ var tests = [
|
|||
PlacesUtils.backups.saveBookmarksToJSONFile(this.file);
|
||||
remove_all_bookmarks();
|
||||
try {
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(this.file);
|
||||
}
|
||||
catch (e) {
|
||||
do_throw(" Restore should not have failed");
|
||||
|
@ -100,7 +100,7 @@ var tests = [
|
|||
run: function () {
|
||||
this.file = createFile("bookmarks-test_restoreNotification.json");
|
||||
try {
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(this.file);
|
||||
}
|
||||
catch (e) {
|
||||
do_throw(" Restore should not have failed");
|
||||
|
@ -118,7 +118,7 @@ var tests = [
|
|||
this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
|
||||
this.file.append("this file doesn't exist because nobody created it");
|
||||
try {
|
||||
PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(this.file);
|
||||
do_throw(" Restore should have failed");
|
||||
}
|
||||
catch (e) {}
|
||||
|
|
|
@ -58,7 +58,7 @@ function run_test() {
|
|||
do_check_false(db.exists());
|
||||
}
|
||||
// Create a corrupt database.
|
||||
corruptDB = gTestDir.clone();
|
||||
let corruptDB = gTestDir.clone();
|
||||
corruptDB.append("corruptDB.sqlite");
|
||||
corruptDB.copyTo(gProfD, "places.sqlite");
|
||||
do_check_true(db.exists());
|
||||
|
|
|
@ -83,7 +83,7 @@ function run_test() {
|
|||
do_check_false(db.exists());
|
||||
}
|
||||
// Create a corrupt database.
|
||||
corruptDB = gTestDir.clone();
|
||||
var corruptDB = gTestDir.clone();
|
||||
corruptDB.append("corruptDB.sqlite");
|
||||
corruptDB.copyTo(gProfD, "places.sqlite");
|
||||
do_check_true(db.exists());
|
||||
|
|
|
@ -83,7 +83,7 @@ function run_test() {
|
|||
do_check_false(db.exists());
|
||||
}
|
||||
// Create a corrupt database.
|
||||
corruptDB = gTestDir.clone();
|
||||
var corruptDB = gTestDir.clone();
|
||||
corruptDB.append("corruptDB.sqlite");
|
||||
corruptDB.copyTo(gProfD, "places.sqlite");
|
||||
do_check_true(db.exists());
|
||||
|
|
|
@ -73,7 +73,7 @@ function run_test() {
|
|||
|
||||
// A migrator would run before nsBrowserGlue, so we mimic that behavior
|
||||
// adding a bookmark.
|
||||
bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
bs.insertBookmark(bs.bookmarksMenuFolder, uri("http://mozilla.org/"),
|
||||
bs.DEFAULT_INDEX, "migrated");
|
||||
|
|
|
@ -789,7 +789,7 @@ function run_test() {
|
|||
folderWChildItemTxn.undoTransaction();
|
||||
do_check_false(bmsvc.isBookmarked(uri("http://www.childItem.com")));
|
||||
folderWChildItemTxn.redoTransaction();
|
||||
newchildItemId = (bmsvc.getBookmarkIdsForURI(uri("http://www.childItem.com"), {}))[0];
|
||||
var newchildItemId = (bmsvc.getBookmarkIdsForURI(uri("http://www.childItem.com"), {}))[0];
|
||||
do_check_eq(observer._itemAddedIndex, 0);
|
||||
do_check_eq(observer._itemAddedId, newchildItemId);
|
||||
do_check_true(bmsvc.isBookmarked(uri("http://www.childItem.com")));
|
||||
|
|
|
@ -364,7 +364,7 @@ PrivateBrowsingService.prototype = {
|
|||
},
|
||||
|
||||
get helpInfo PBS_get_helpInfo() {
|
||||
return " -private Enable private browsing mode.\n";
|
||||
return " -private Enable private browsing mode.\n";
|
||||
},
|
||||
|
||||
// nsIPrivateBrowsingService
|
||||
|
|
|
@ -80,35 +80,44 @@ function test() {
|
|||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
// ensure that the test is run after the titlebar has been updated
|
||||
let timer = null;
|
||||
let _updateTitlebar = gBrowser.updateTitlebar;
|
||||
gBrowser.updateTitlebar = function() {
|
||||
if (timer) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
timer = Cc["@mozilla.org/timer;1"].
|
||||
createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(function () {
|
||||
_updateTitlebar.apply(gBrowser, arguments);
|
||||
gBrowser.updateTitlebar = _updateTitlebar;
|
||||
is(document.title, expected_title, "The window title for " + url +
|
||||
" is correct (" + (insidePB ? "inside" : "outside") +
|
||||
" private browsing mode)");
|
||||
|
||||
// ensure that the test is run after the page onload event
|
||||
setTimeout(function() {
|
||||
setTimeout(function() {
|
||||
is(document.title, expected_title, "The window title for " + url +
|
||||
" is correct (" + (insidePB ? "inside" : "outside") +
|
||||
" private browsing mode)");
|
||||
let win = gBrowser.replaceTabWithWindow(tab);
|
||||
win.addEventListener("load", function() {
|
||||
win.removeEventListener("load", arguments.callee, false);
|
||||
|
||||
let win = gBrowser.replaceTabWithWindow(tab);
|
||||
win.addEventListener("load", function() {
|
||||
win.removeEventListener("load", arguments.callee, false);
|
||||
// ensure that the test is run after delayedStartup
|
||||
let _delayedStartup = win.delayedStartup;
|
||||
win.delayedStartup = function() {
|
||||
_delayedStartup.apply(win, arguments);
|
||||
win.delayedStartup = _delayedStartup;
|
||||
|
||||
// ensure that the test is run after delayedStartup
|
||||
setTimeout(function() {
|
||||
setTimeout(function() {
|
||||
is(win.document.title, expected_title, "The window title for " + url +
|
||||
" detahced tab is correct (" + (insidePB ? "inside" : "outside") +
|
||||
" private browsing mode)");
|
||||
win.close();
|
||||
is(win.document.title, expected_title, "The window title for " + url +
|
||||
" detached tab is correct (" + (insidePB ? "inside" : "outside") +
|
||||
" private browsing mode)");
|
||||
win.close();
|
||||
|
||||
setTimeout(funcNext, 0);
|
||||
};
|
||||
}, false);
|
||||
}, 300, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
};
|
||||
|
||||
funcNext();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, false);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, true);
|
||||
browser.loadURI(url);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
# browser_477657.js is disabled, because it's unreliable (bug 482975).
|
||||
# browser_480148.js is disabled, because it breaks browser_420786.js (see bug 483382).
|
||||
# tests for 459906, 463205, and 464620 disabled because they are broken.
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_248970_a.js \
|
||||
|
@ -75,13 +74,23 @@ _BROWSER_TEST_FILES = \
|
|||
browser_454908_sample.html \
|
||||
browser_456342.js \
|
||||
browser_456342_sample.xhtml \
|
||||
browser_459906.js \
|
||||
browser_459906_empty.html \
|
||||
browser_459906_sample.html \
|
||||
browser_461634.js \
|
||||
browser_461743.js \
|
||||
browser_461743_sample.html \
|
||||
browser_463205.js \
|
||||
browser_463205_helper.html \
|
||||
browser_463205_sample.html \
|
||||
browser_463206.js \
|
||||
browser_463206_sample.html \
|
||||
browser_464199.js \
|
||||
browser_464620_a.js \
|
||||
browser_464620_a.html \
|
||||
browser_464620_b.js \
|
||||
browser_464620_b.html \
|
||||
browser_464620_xd.html \
|
||||
browser_465215.js \
|
||||
browser_465223.js \
|
||||
browser_466937.js \
|
||||
|
|
|
@ -58,54 +58,56 @@ function test() {
|
|||
|
||||
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", testURL);
|
||||
newWin.addEventListener("load", function(aEvent) {
|
||||
newWin.removeEventListener("load", arguments.callee, false);
|
||||
newWin.gBrowser.addEventListener("load", function(aEvent) {
|
||||
newWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
executeSoon(function() {
|
||||
newWin.gBrowser.addTab();
|
||||
executeSoon(function() {
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(newWin, uniqueKey, uniqueValue);
|
||||
let textbox = newWin.content.document.getElementById("textbox");
|
||||
textbox.wrappedJSObject.value = uniqueText;
|
||||
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(newWin, uniqueKey, uniqueValue);
|
||||
let textbox = newWin.content.document.getElementById("textbox");
|
||||
textbox.wrappedJSObject.value = uniqueText;
|
||||
newWin.close();
|
||||
|
||||
newWin.close();
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The closed window was added to Recently Closed Windows");
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.title == testURL && data.toSource().indexOf(uniqueText) > -1,
|
||||
"The closed window data was stored correctly");
|
||||
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The closed window was added to Recently Closed Windows");
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.title == testURL && data.toSource().indexOf(uniqueText) > -1,
|
||||
"The closed window data was stored correctly");
|
||||
// reopen the closed window and ensure its integrity
|
||||
let newWin2 = ss.undoCloseWindow(0);
|
||||
|
||||
// reopen the closed window and ensure its integrity
|
||||
let newWin2 = ss.undoCloseWindow(0);
|
||||
ok(newWin2 instanceof ChromeWindow,
|
||||
"undoCloseWindow actually returned a window");
|
||||
is(ss.getClosedWindowCount(), closedWindowCount,
|
||||
"The reopened window was removed from Recently Closed Windows");
|
||||
|
||||
ok(newWin2 instanceof ChromeWindow,
|
||||
"undoCloseWindow actually returned a window");
|
||||
is(ss.getClosedWindowCount(), closedWindowCount,
|
||||
"The reopened window was removed from Recently Closed Windows");
|
||||
newWin2.addEventListener("load", function(aEvent) {
|
||||
newWin2.gBrowser.addEventListener("SSTabRestored", function(aEvent) {
|
||||
newWin2.gBrowser.removeEventListener("SSTabRestored", arguments.callee, true);
|
||||
|
||||
newWin2.addEventListener("load", function(aEvent) {
|
||||
newWin2.gBrowser.addEventListener("SSTabRestored", function(aEvent) {
|
||||
newWin2.gBrowser.removeEventListener("SSTabRestored", arguments.callee, true);
|
||||
is(newWin2.gBrowser.tabContainer.childNodes.length, 2,
|
||||
"The window correctly restored 2 tabs");
|
||||
is(newWin2.gBrowser.currentURI.spec, testURL,
|
||||
"The window correctly restored the URL");
|
||||
|
||||
is(newWin2.gBrowser.tabContainer.childNodes.length, 2,
|
||||
"The window correctly restored 2 tabs");
|
||||
is(newWin2.gBrowser.currentURI.spec, testURL,
|
||||
"The window correctly restored the URL");
|
||||
let textbox = newWin2.content.document.getElementById("textbox");
|
||||
is(textbox.wrappedJSObject.value, uniqueText,
|
||||
"The window correctly restored the form");
|
||||
is(ss.getWindowValue(newWin2, uniqueKey), uniqueValue,
|
||||
"The window correctly restored the data associated with it");
|
||||
|
||||
let textbox = newWin2.content.document.getElementById("textbox");
|
||||
is(textbox.wrappedJSObject.value, uniqueText,
|
||||
"The window correctly restored the form");
|
||||
is(ss.getWindowValue(newWin2, uniqueKey), uniqueValue,
|
||||
"The window correctly restored the data associated with it");
|
||||
|
||||
// clean up
|
||||
newWin2.close();
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
|
||||
executeSoon(callback);
|
||||
}, true);
|
||||
}, false);
|
||||
// clean up
|
||||
newWin2.close();
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
|
||||
executeSoon(callback);
|
||||
}, true);
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
}, true);
|
||||
}, false);
|
||||
|
|
|
@ -77,6 +77,7 @@ function test() {
|
|||
ss.setBrowserState(blankState);
|
||||
|
||||
let closedWindowCount = ss.getClosedWindowCount();
|
||||
is(closedWindowCount, 0, "Correctly set window count");
|
||||
|
||||
let testURL_A = "about:config";
|
||||
let testURL_B = "about:mozilla";
|
||||
|
@ -90,77 +91,81 @@ function test() {
|
|||
// Open a window
|
||||
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", testURL_A);
|
||||
newWin.addEventListener("load", function(aEvent) {
|
||||
newWin.removeEventListener("load", arguments.callee, false);
|
||||
newWin.gBrowser.addEventListener("load", function(aEvent) {
|
||||
newWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
info("Window has been loaded");
|
||||
executeSoon(function() {
|
||||
newWin.gBrowser.addTab();
|
||||
executeSoon(function() {
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(newWin, uniqueKey_A, uniqueValue_A);
|
||||
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(newWin, uniqueKey_A, uniqueValue_A);
|
||||
newWin.close();
|
||||
|
||||
newWin.close();
|
||||
// ensure that we incremented # of close windows
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The closed window was added to the list");
|
||||
|
||||
// ensure that we incremented # of close windows
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The closed window was added to the list");
|
||||
// ensure we added window to undo list
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_A) > -1,
|
||||
"The closed window data was stored correctly");
|
||||
|
||||
// ensure we added window to undo list
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_A) > -1,
|
||||
"The closed window data was stored correctly");
|
||||
// enter private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
ok(pb.privateBrowsingEnabled, "private browsing enabled");
|
||||
|
||||
// enter private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
ok(pb.privateBrowsingEnabled, "private browsing enabled");
|
||||
// ensure that we have 0 undo windows when entering PB
|
||||
is(ss.getClosedWindowCount(), 0,
|
||||
"Recently Closed Windows are removed when entering Private Browsing");
|
||||
is(ss.getClosedWindowData(), "[]",
|
||||
"Recently Closed Windows data is cleared when entering Private Browsing");
|
||||
|
||||
// ensure that we have 0 undo windows when entering PB
|
||||
is(ss.getClosedWindowCount(), 0,
|
||||
"Recently Closed Windows are removed when entering Private Browsing");
|
||||
is(ss.getClosedWindowData(), "[]",
|
||||
"Recently Closed Windows data is cleared when entering Private Browsing");
|
||||
// open another window in PB
|
||||
let pbWin = openDialog(location, "_blank", "chrome,all,dialog=no", testURL_B);
|
||||
pbWin.addEventListener("load", function(aEvent) {
|
||||
pbWin.removeEventListener("load", arguments.callee, false);
|
||||
pbWin.gBrowser.addEventListener("load", function(aEvent) {
|
||||
pbWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
// open another window in PB
|
||||
let pbWin = openDialog(location, "_blank", "chrome,all,dialog=no", testURL_B);
|
||||
pbWin.addEventListener("load", function(aEvent) {
|
||||
pbWin.gBrowser.addEventListener("load", function(aEvent) {
|
||||
pbWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
// Add another tab, though it's not strictly needed
|
||||
pbWin.gBrowser.addTab();
|
||||
executeSoon(function() {
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(pbWin, uniqueKey_B, uniqueValue_B);
|
||||
|
||||
executeSoon(function() {
|
||||
// Add another tab, though it's not strictly needed
|
||||
pbWin.gBrowser.addTab();
|
||||
pbWin.close();
|
||||
|
||||
// mark the window with some unique data to be restored later on
|
||||
ss.setWindowValue(pbWin, uniqueKey_B, uniqueValue_B);
|
||||
// ensure we added window to undo list
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_B) > -1,
|
||||
"The closed window data was stored correctly in PB mode");
|
||||
|
||||
pbWin.close();
|
||||
// exit private browsing mode
|
||||
pb.privateBrowsingEnabled = false;
|
||||
ok(!pb.privateBrowsingEnabled, "private browsing disabled");
|
||||
|
||||
// ensure we added window to undo list
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_B) > -1,
|
||||
"The closed window data was stored correctly in PB mode");
|
||||
// ensure that we still have the closed windows from before
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The correct number of recently closed windows were restored " +
|
||||
"when exiting PB mode");
|
||||
|
||||
// exit private browsing mode
|
||||
pb.privateBrowsingEnabled = false;
|
||||
ok(!pb.privateBrowsingEnabled, "private browsing disabled");
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_A) > -1,
|
||||
"The data associated with the recently closed window was " +
|
||||
"restored when exiting PB mode");
|
||||
|
||||
// ensure that we still have the closed windows from before
|
||||
is(ss.getClosedWindowCount(), closedWindowCount + 1,
|
||||
"The correct number of recently closed windows were restored " +
|
||||
"when exiting PB mode");
|
||||
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
ok(data.toSource().indexOf(uniqueValue_A) > -1,
|
||||
"The data associated with the recently closed window was " +
|
||||
"restored when exiting PB mode");
|
||||
|
||||
// cleanup
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
finish();
|
||||
});
|
||||
}, true);
|
||||
}, true);
|
||||
// cleanup
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}, true);
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
}, true);
|
||||
}, true);
|
||||
}, false);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ nsSetDefaultBrowser.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
helpInfo: " -setDefaultBrowser Set this app as the default browser.\n",
|
||||
helpInfo: " -setDefaultBrowser Set this app as the default browser.\n",
|
||||
|
||||
classDescription: "Default Browser Cmdline Handler",
|
||||
contractID: "@mozilla.org/browser/default-browser-clh;1",
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
# The Original Code is Aero Peek
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2001
|
||||
# Mozilla Corporation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Rob Arnold <tellrob@gmail.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
|
||||
|
@ -34,47 +35,22 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../../../..
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = printpde
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
MODULE = wintaskbar
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
WindowsPreviewPerTab.jsm \
|
||||
WindowsJumpLists.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifdef MOZ_DEBUG
|
||||
BUILDSTYLE = Development
|
||||
else
|
||||
BUILDSTYLE = Deployment
|
||||
endif
|
||||
|
||||
# pbbuild or xcodebuild indicates Xcode; the Xcode project contains
|
||||
# native targets needed for proper SDK builds.
|
||||
PROJECT=PrintPDE.xcode
|
||||
PROJECT_ARG=-project $(PROJECT)
|
||||
PBBUILD_ARG=$(PBBUILD_SETTINGS)
|
||||
|
||||
unexport CC CXX
|
||||
|
||||
ABS_topsrcdir := $(shell cd $(topsrcdir); pwd)
|
||||
ifneq ($(ABS_topsrcdir),$(MOZ_BUILD_ROOT))
|
||||
export::
|
||||
rsync -a --exclude .DS_Store --exclude "CVS/" $(srcdir)/$(PROJECT) .
|
||||
ln -fs $(srcdir)/src
|
||||
ln -fs $(srcdir)/res
|
||||
ln -fs $(srcdir)/public
|
||||
ln -fs $(srcdir)/Info-*.plist .
|
||||
|
||||
GARBAGE += src res public Info-*.plist
|
||||
GARBAGE_DIRS += $(PROJECT)
|
||||
endif
|
||||
|
||||
GARBAGE_DIRS += build
|
||||
|
||||
libs::
|
||||
$(PBBUILD) $(PROJECT_ARG) -target PrintPDE -buildstyle $(BUILDSTYLE) $(PBBUILD_ARG)
|
||||
mkdir -p $(DIST)/package
|
||||
$(INSTALL) $(XCODE_PRODUCT_DIR)/PrintPDE.plugin $(DIST)/package
|
|
@ -0,0 +1,528 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jim Mathies <jmathies@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 ***** */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// Prefs
|
||||
const PREF_TASKBAR_BRANCH = "browser.taskbar.lists.";
|
||||
const PREF_TASKBAR_ENABLED = "enabled";
|
||||
const PREF_TASKBAR_ITEMCOUNT = "maxListItemCount";
|
||||
const PREF_TASKBAR_FREQUENT = "frequent.enabled";
|
||||
const PREF_TASKBAR_RECENT = "recent.enabled";
|
||||
const PREF_TASKBAR_TASKS = "tasks.enabled";
|
||||
|
||||
// The amount of time between updates for jump lists
|
||||
const TIMER_TASKBAR_REFRESH = 1000*60*2; // 2 min.
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
let EXPORTED_SYMBOLS = [
|
||||
"WinTaskbarJumpList",
|
||||
];
|
||||
|
||||
/**
|
||||
* Smart getters
|
||||
*/
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "_prefs", function() {
|
||||
return Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefService)
|
||||
.getBranch(PREF_TASKBAR_BRANCH)
|
||||
.QueryInterface(Ci.nsIPrefBranch2);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "_stringBundle", function() {
|
||||
return Cc["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Ci.nsIStringBundleService)
|
||||
.createBundle("chrome://browser/locale/taskbar.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService",
|
||||
"@mozilla.org/windows-taskbar;1",
|
||||
"nsIWinTaskbar");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_navHistoryService",
|
||||
"@mozilla.org/browser/nav-history-service;1",
|
||||
"nsINavHistoryService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_observerService",
|
||||
"@mozilla.org/observer-service;1",
|
||||
"nsIObserverService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_directoryService",
|
||||
"@mozilla.org/file/directory_service;1",
|
||||
"nsIProperties");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_ioService",
|
||||
"@mozilla.org/network/io-service;1",
|
||||
"nsIIOService");
|
||||
|
||||
/**
|
||||
* Global functions
|
||||
*/
|
||||
|
||||
function _getString(name) {
|
||||
return _stringBundle.GetStringFromName(name);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Task list configuration data object.
|
||||
|
||||
var tasksCfg = [
|
||||
/**
|
||||
* Task configuration options: title, description, args, iconIndex, open, close.
|
||||
*
|
||||
* title - Task title displayed in the list. (strings in the table are temp fillers.)
|
||||
* description - Tooltip description on the list item.
|
||||
* args - Command line args to invoke the task.
|
||||
* iconIndex - Optional win icon index into the main application for the
|
||||
* list item.
|
||||
* open - Boolean indicates if the command should be visible after the browser opens.
|
||||
* close - Boolean indicates if the command should be visible after the browser closes.
|
||||
*/
|
||||
// Open new window
|
||||
{
|
||||
get title() _getString("taskbar.tasks.newTab.label"),
|
||||
get description() _getString("taskbar.tasks.newTab.description"),
|
||||
args: "-new-tab about:blank",
|
||||
iconIndex: 0, // Fx app icon
|
||||
open: true,
|
||||
close: false, // The jump list already has an app launch icon
|
||||
},
|
||||
|
||||
// Open new tab
|
||||
{
|
||||
get title() _getString("taskbar.tasks.newWindow.label"),
|
||||
get description() _getString("taskbar.tasks.newWindow.description"),
|
||||
args: "-browser",
|
||||
iconIndex: 0, // Fx app icon
|
||||
open: true,
|
||||
close: false, // no point
|
||||
},
|
||||
];
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation
|
||||
|
||||
var WinTaskbarJumpList =
|
||||
{
|
||||
_builder: null,
|
||||
_tasks: null,
|
||||
_shuttingDown: false,
|
||||
|
||||
/**
|
||||
* Startup, shutdown, and update
|
||||
*/
|
||||
|
||||
startup: function WTBJL_startup() {
|
||||
// exit if this isn't win7 or higher.
|
||||
if (!this._initTaskbar())
|
||||
return;
|
||||
|
||||
// Store our task list config data
|
||||
this._tasks = tasksCfg;
|
||||
|
||||
// retrieve taskbar related prefs.
|
||||
this._refreshPrefs();
|
||||
|
||||
// observer for private browsing and our prefs branch
|
||||
this._initObs();
|
||||
|
||||
// jump list refresh timer
|
||||
this._initTimer();
|
||||
|
||||
// build the list
|
||||
this.update();
|
||||
},
|
||||
|
||||
update: function WTBJL_update() {
|
||||
// are we disabled via prefs? don't do anything!
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
// hide jump lists when we're enabled and in private browsing mode
|
||||
if (this._inPrivateBrowsing) {
|
||||
this._deleteActiveJumpList();
|
||||
return;
|
||||
}
|
||||
|
||||
// do what we came here to do, update the taskbar jumplist
|
||||
this._buildList();
|
||||
},
|
||||
|
||||
_shutdown: function WTBJL__shutdown() {
|
||||
this._shuttingDown = true;
|
||||
this.update();
|
||||
this._free();
|
||||
},
|
||||
|
||||
/**
|
||||
* List building
|
||||
*/
|
||||
|
||||
_buildList: function WTBJL__buildList() {
|
||||
// anything to build?
|
||||
if (!this._showFrequent && !this._showRecent && !this._showTasks) {
|
||||
// don't leave the last list hanging on the taskbar.
|
||||
this._deleteActiveJumpList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._startBuild())
|
||||
return;
|
||||
|
||||
if (this._showTasks && !this._buildTasks())
|
||||
return;
|
||||
|
||||
// Space for frequent items takes priority over recent.
|
||||
|
||||
if (this._showFrequent && !this._buildFrequent())
|
||||
return;
|
||||
|
||||
if (this._showRecent && !this._buildRecent())
|
||||
return;
|
||||
|
||||
this._commitBuild();
|
||||
},
|
||||
|
||||
/**
|
||||
* Taskbar api wrappers
|
||||
*/
|
||||
|
||||
_startBuild: function WTBJL__startBuild() {
|
||||
var removedItems = Cc["@mozilla.org/array;1"].
|
||||
createInstance(Ci.nsIMutableArray);
|
||||
this._builder.abortListBuild();
|
||||
if (this._builder.initListBuild(removedItems)) {
|
||||
// Prior to building, delete removed items from history.
|
||||
this._clearHistory(removedItems);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_commitBuild: function WTBJL__commitBuild() {
|
||||
if (!this._builder.commitListBuild())
|
||||
this._builder.abortListBuild();
|
||||
},
|
||||
|
||||
_buildTasks: function WTBJL__buildTasks() {
|
||||
var items = Cc["@mozilla.org/array;1"].
|
||||
createInstance(Ci.nsIMutableArray);
|
||||
this._tasks.forEach(function (task) {
|
||||
if ((this._shuttingDown && !task.close) || (!this._shuttingDown && !task.open))
|
||||
return;
|
||||
var item = this._getHandlerAppItem(task.title, task.description,
|
||||
task.args, task.iconIndex);
|
||||
items.appendElement(item, false);
|
||||
}, this);
|
||||
|
||||
if (items.length == 0)
|
||||
return true;
|
||||
|
||||
return this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_TASKS, items);
|
||||
},
|
||||
|
||||
_buildCustom: function WTBJL__buildCustom(title, items) {
|
||||
if (items.length == 0)
|
||||
return true;
|
||||
return this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_CUSTOMLIST, items, title);
|
||||
},
|
||||
|
||||
_buildFrequent: function WTBJL__buildFrequent() {
|
||||
// Windows supports default frequent and recent lists,
|
||||
// but those depend on internal windows visit tracking
|
||||
// which we don't populate. So we build our own custom
|
||||
// frequent and recent lists using our nav history data.
|
||||
|
||||
var items = Cc["@mozilla.org/array;1"].
|
||||
createInstance(Ci.nsIMutableArray);
|
||||
var list = this._getNavFrequent(this._maxItemCount);
|
||||
|
||||
if (!list || list.length == 0)
|
||||
return true;
|
||||
|
||||
// track frequent items so that we don't add them to
|
||||
// the recent list.
|
||||
this._frequentHashList = [];
|
||||
|
||||
list.forEach(function (entry) {
|
||||
let shortcut = this._getHandlerAppItem(entry.title, entry.title, entry.uri, 1);
|
||||
items.appendElement(shortcut, false);
|
||||
this._frequentHashList.push(entry.uri);
|
||||
}, this);
|
||||
return this._buildCustom(_getString("taskbar.frequent.label"), items);
|
||||
},
|
||||
|
||||
_buildRecent: function WTBJL__buildRecent() {
|
||||
var items = Cc["@mozilla.org/array;1"].
|
||||
createInstance(Ci.nsIMutableArray);
|
||||
var list = this._getNavRecent(this._maxItemCount*2);
|
||||
|
||||
if (!list || list.length == 0)
|
||||
return true;
|
||||
|
||||
let count = 0;
|
||||
for (let idx = 0; idx < list.length; idx++) {
|
||||
if (count >= this._maxItemCount)
|
||||
break;
|
||||
let entry = list[idx];
|
||||
// do not add items to recent that have already been added
|
||||
// to frequent.
|
||||
if (this._frequentHashList &&
|
||||
this._frequentHashList.indexOf(entry.uri) != -1)
|
||||
continue;
|
||||
let shortcut = this._getHandlerAppItem(entry.title, entry.title, entry.uri, 1);
|
||||
items.appendElement(shortcut, false);
|
||||
count++;
|
||||
}
|
||||
return this._buildCustom(_getString("taskbar.recent.label"), items);
|
||||
},
|
||||
|
||||
_deleteActiveJumpList: function WTBJL__deleteAJL() {
|
||||
return this._builder.deleteActiveList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Jump list item creation helpers
|
||||
*/
|
||||
|
||||
_getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, args, icon) {
|
||||
var file = _directoryService.get("XCurProcD", Ci.nsILocalFile);
|
||||
|
||||
// XXX where can we grab this from in the build? Do we need to?
|
||||
file.append("firefox.exe");
|
||||
|
||||
var handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
|
||||
createInstance(Ci.nsILocalHandlerApp);
|
||||
handlerApp.executable = file;
|
||||
// handlers default to the leaf name if a name is not specified
|
||||
if (name.length != 0)
|
||||
handlerApp.name = name;
|
||||
handlerApp.detailedDescription = description;
|
||||
handlerApp.appendParameter(args);
|
||||
|
||||
var item = Cc["@mozilla.org/windows-jumplistshortcut;1"].
|
||||
createInstance(Ci.nsIJumpListShortcut);
|
||||
item.app = handlerApp;
|
||||
item.iconIndex = icon;
|
||||
return item;
|
||||
},
|
||||
|
||||
_getSeparatorItem: function WTBJL__getSeparatorItem() {
|
||||
var item = Cc["@mozilla.org/windows-jumplistseparator;1"].
|
||||
createInstance(Ci.nsIJumpListSeparator);
|
||||
return item;
|
||||
},
|
||||
|
||||
/**
|
||||
* Nav history helpers
|
||||
*/
|
||||
|
||||
_getNavFrequent: function WTBJL__getNavFrequent(depth) {
|
||||
var options = _navHistoryService.getNewQueryOptions();
|
||||
var query = _navHistoryService.getNewQuery();
|
||||
|
||||
query.beginTimeReference = query.TIME_RELATIVE_NOW;
|
||||
query.beginTime = -24 * 30 * 60 * 60 * 1000000; // one month
|
||||
query.endTimeReference = query.TIME_RELATIVE_NOW;
|
||||
|
||||
options.maxResults = depth;
|
||||
options.queryType = options.QUERY_TYPE_HISTORY;
|
||||
options.sortingMode = options.SORT_BY_VISITCOUNT_DESCENDING;
|
||||
options.resultType = options.RESULT_TYPE_URI;
|
||||
|
||||
var result = _navHistoryService.executeQuery(query, options);
|
||||
|
||||
var list = [];
|
||||
|
||||
var rootNode = result.root;
|
||||
rootNode.containerOpen = true;
|
||||
|
||||
for (let idx = 0; idx < rootNode.childCount; idx++) {
|
||||
let node = rootNode.getChild(idx);
|
||||
list.push({uri: node.uri, title: node.title});
|
||||
}
|
||||
rootNode.containerOpen = false;
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
_getNavRecent: function WTBJL__getNavRecent(depth) {
|
||||
var options = _navHistoryService.getNewQueryOptions();
|
||||
var query = _navHistoryService.getNewQuery();
|
||||
|
||||
query.beginTimeReference = query.TIME_RELATIVE_NOW;
|
||||
query.beginTime = -48 * 60 * 60 * 1000000; // two days
|
||||
query.endTimeReference = query.TIME_RELATIVE_NOW;
|
||||
|
||||
options.maxResults = depth;
|
||||
options.queryType = options.QUERY_TYPE_HISTORY;
|
||||
options.sortingMode = options.SORT_BY_LASTMODIFIED_DESCENDING;
|
||||
options.resultType = options.RESULT_TYPE_URI;
|
||||
|
||||
var result = _navHistoryService.executeQuery(query, options);
|
||||
|
||||
var list = [];
|
||||
|
||||
var rootNode = result.root;
|
||||
rootNode.containerOpen = true;
|
||||
|
||||
for (var idx = 0; idx < rootNode.childCount; idx++) {
|
||||
var node = rootNode.getChild(idx);
|
||||
list.push({uri: node.uri, title: node.title});
|
||||
}
|
||||
rootNode.containerOpen = false;
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
_clearHistory: function WTBJL__clearHistory(items) {
|
||||
if (!items)
|
||||
return;
|
||||
var enum = items.enumerate();
|
||||
while (enum.hasMoreElements()) {
|
||||
let oldItem = enum.getNext().QueryInterface(Ci.nsIJumpListShortcut);
|
||||
if (oldItem) {
|
||||
try { // in case we get a bad uri
|
||||
let uriSpec = oldItem.app.getParameter(0);
|
||||
_navHistoryService.QueryInterface(Ci.nsIBrowserHistory).removePage(
|
||||
_ioService.newURI(uriSpec));
|
||||
} catch (err) { }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Prefs utilities
|
||||
*/
|
||||
|
||||
_refreshPrefs: function WTBJL__refreshPrefs() {
|
||||
this._enabled = _prefs.getBoolPref(PREF_TASKBAR_ENABLED);
|
||||
this._showFrequent = _prefs.getBoolPref(PREF_TASKBAR_FREQUENT);
|
||||
this._showRecent = _prefs.getBoolPref(PREF_TASKBAR_RECENT);
|
||||
this._showTasks = _prefs.getBoolPref(PREF_TASKBAR_TASKS);
|
||||
this._maxItemCount = _prefs.getIntPref(PREF_TASKBAR_ITEMCOUNT);
|
||||
|
||||
// retrieve the initial status of the Private Browsing mode.
|
||||
this._inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService).
|
||||
privateBrowsingEnabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Init and shutdown utilities
|
||||
*/
|
||||
|
||||
_initTaskbar: function WTBJL__initTaskbar() {
|
||||
this._builder = _taskbarService.createJumpListBuilder();
|
||||
if (!this._builder || !this._builder.available)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_initObs: function WTBJL__initObs() {
|
||||
_observerService.addObserver(this, "private-browsing", false);
|
||||
_observerService.addObserver(this, "quit-application-granted", false);
|
||||
_prefs.addObserver("", this, false);
|
||||
},
|
||||
|
||||
_freeObs: function WTBJL__freeObs() {
|
||||
_observerService.removeObserver(this, "private-browsing");
|
||||
_observerService.removeObserver(this, "quit-application-granted");
|
||||
_prefs.removeObserver("", this);
|
||||
},
|
||||
|
||||
_initTimer: function WTBJL__initTimer(aTimer) {
|
||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._timer.initWithCallback(this, TIMER_TASKBAR_REFRESH, this._timer.TYPE_REPEATING_SLACK);
|
||||
},
|
||||
|
||||
_free: function WTBJL__free() {
|
||||
this._freeObs();
|
||||
delete this._builder;
|
||||
delete this._timer;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notification handlers
|
||||
*/
|
||||
|
||||
notify: function WTBJL_notify(aTimer) {
|
||||
this.update();
|
||||
},
|
||||
|
||||
observe: function WTBJL_observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
this._refreshPrefs();
|
||||
this.update();
|
||||
break;
|
||||
|
||||
case "quit-application-granted":
|
||||
this._shutdown();
|
||||
break;
|
||||
|
||||
case "browser:purge-session-history":
|
||||
this.update();
|
||||
break;
|
||||
|
||||
case "private-browsing":
|
||||
switch (aData) {
|
||||
case "enter":
|
||||
this._inPrivateBrowsing = true;
|
||||
break;
|
||||
case "exit":
|
||||
this._inPrivateBrowsing = false;
|
||||
break;
|
||||
}
|
||||
this.update();
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
|
@ -0,0 +1,653 @@
|
|||
/* vim: se cin sw=2 ts=2 et :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Arnold <robarnold@cmu.edu> (original author)
|
||||
*
|
||||
* 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 ***** */
|
||||
/*
|
||||
* This module implements the front end behavior for AeroPeek. Starting in
|
||||
* Windows Vista, the taskbar began showing live thumbnail previews of windows
|
||||
* when the user hovered over the window icon in the taskbar. Starting with
|
||||
* Windows 7, the taskbar allows an application to expose its tabbed interface
|
||||
* in the taskbar by showing thumbnail previews rather than the default window
|
||||
* preview. Additionally, when a user hovers over a thumbnail (tab or window),
|
||||
* they are shown a live preview of the window (or tab + its containing window).
|
||||
*
|
||||
* In Windows 7, a title, icon, close button and optional toolbar are shown for
|
||||
* each preview. This feature does not make use of the toolbar. For window
|
||||
* previews, the title is the window title and the icon the window icon. For
|
||||
* tab previews, the title is the page title and the page's favicon. In both
|
||||
* cases, the close button "does the right thing."
|
||||
*
|
||||
* The primary objects behind this feature are nsITaskbarTabPreview and
|
||||
* nsITaskbarPreviewController. Each preview has a controller. The controller
|
||||
* responds to the user's interactions on the taskbar and provides the required
|
||||
* data to the preview for determining the size of the tab and thumbnail. The
|
||||
* PreviewController class implements this interface. The preview will request
|
||||
* the controller to provide a thumbnail or preview when the user interacts with
|
||||
* the taskbar. To reduce the overhead of drawing the tab area, the controller
|
||||
* implementation caches the tab's contents in a <canvas> element. If no
|
||||
* previews or thumbnails have been requested for some time, the controller will
|
||||
* discard its cached tab contents.
|
||||
*
|
||||
* Screen real estate is limited so when there are too many thumbnails to fit
|
||||
* on the screen, the taskbar stops displaying thumbnails and instead displays
|
||||
* just the title, icon and close button in a similar fashion to previous
|
||||
* versions of the taskbar. If there are still too many previews to fit on the
|
||||
* screen, the taskbar resorts to a scroll up and scroll down button pair to let
|
||||
* the user scroll through the list of tabs. Since this is undoubtedly
|
||||
* inconvenient for users with many tabs, the AeroPeek objects turns off all of
|
||||
* the tab previews. This tells the taskbar to revert to one preview per window.
|
||||
* If the number of tabs falls below this magic threshold, the preview-per-tab
|
||||
* behavior returns. There is no reliable way to determine when the scroll
|
||||
* buttons appear on the taskbar, so a magic pref-controlled number determines
|
||||
* when this threshold has been crossed.
|
||||
*/
|
||||
var EXPORTED_SYMBOLS = ["AeroPeek"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// Pref to enable/disable preview-per-tab
|
||||
const TOGGLE_PREF_NAME = "browser.taskbar.previews.enable";
|
||||
// Pref to determine the magic auto-disable threshold
|
||||
const DISABLE_THRESHOLD_PREF_NAME = "browser.taskbar.previews.max";
|
||||
// Pref to control the time in seconds that tab contents live in the cache
|
||||
const CACHE_EXPIRATION_TIME_PREF_NAME = "browser.taskbar.previews.cachetime";
|
||||
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Various utility properties
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ioSvc",
|
||||
"@mozilla.org/network/io-service;1",
|
||||
"nsIIOService");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "imgTools",
|
||||
"@mozilla.org/image/tools;1",
|
||||
"imgITools");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "faviconSvc",
|
||||
"@mozilla.org/browser/favicon-service;1",
|
||||
"nsIFaviconService");
|
||||
|
||||
// nsIURI -> imgIContainer
|
||||
function _imageFromURI(uri) {
|
||||
let channel = ioSvc.newChannelFromURI(uri);
|
||||
|
||||
let out_img = { value: null };
|
||||
let inputStream = channel.open();
|
||||
try {
|
||||
imgTools.decodeImageData(inputStream, channel.contentType, out_img);
|
||||
return out_img.value;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// string -> imgIContainer
|
||||
function _imageFromURL(url) {
|
||||
return _imageFromURI(NetUtil.newURI(url));
|
||||
}
|
||||
|
||||
// string? -> imgIContainer
|
||||
function getFaviconAsImage(iconurl) {
|
||||
return (iconurl ? _imageFromURL(iconurl) : false) ||
|
||||
_imageFromURI(faviconSvc.defaultFavicon);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// PreviewController
|
||||
|
||||
/*
|
||||
* This class manages the behavior of the preview.
|
||||
*
|
||||
* To give greater performance when drawing, the dirty areas of the content
|
||||
* window are tracked and drawn on demand into a canvas of the same size.
|
||||
* This provides a great increase in responsiveness when drawing a preview
|
||||
* for unchanged (or even only slightly changed) tabs.
|
||||
*
|
||||
* @param win
|
||||
* The TabWindow (see below) that owns the preview that this controls
|
||||
* @param tab
|
||||
* The <tab> that this preview is associated with
|
||||
*/
|
||||
function PreviewController(win, tab) {
|
||||
this.win = win;
|
||||
this.tab = tab;
|
||||
this.linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
this.linkedBrowser.addEventListener("MozAfterPaint", this, false);
|
||||
this.linkedBrowser.addEventListener("DOMTitleChanged", this, false);
|
||||
// pageshow is needed for when a tab is dragged across windows.
|
||||
this.linkedBrowser.addEventListener("pageshow", this, false);
|
||||
|
||||
// Cannot perform the lookup during construction. See TabWindow.newTab
|
||||
XPCOMUtils.defineLazyGetter(this, "preview", function () this.win.previewFromTab(this.tab));
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "canvasPreview", function ()
|
||||
this.win.win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"));
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "dirtyRegion",
|
||||
function () {
|
||||
let dirtyRegion = Cc["@mozilla.org/gfx/region;1"]
|
||||
.createInstance(Ci.nsIScriptableRegion);
|
||||
dirtyRegion.init();
|
||||
return dirtyRegion;
|
||||
});
|
||||
}
|
||||
|
||||
PreviewController.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITaskbarPreviewController,
|
||||
Ci.nsIDOMEventListener]),
|
||||
destroy: function () {
|
||||
this.linkedBrowser.removeEventListener("pageshow", this, false);
|
||||
this.linkedBrowser.removeEventListener("DOMTitleChanged", this, false);
|
||||
this.linkedBrowser.removeEventListener("MozAfterPaint", this, false);
|
||||
},
|
||||
get wrappedJSObject() {
|
||||
return this;
|
||||
},
|
||||
|
||||
get dirtyRects() {
|
||||
let rectstream = this.dirtyRegion.getRects();
|
||||
if (!rectstream)
|
||||
return [];
|
||||
let rects = [];
|
||||
for (let i = 0; i < rectstream.length; i+= 4) {
|
||||
let r = {x: rectstream[i],
|
||||
y: rectstream[i+1],
|
||||
width: rectstream[i+2],
|
||||
height: rectstream[i+3]};
|
||||
rects.push(r);
|
||||
}
|
||||
return rects;
|
||||
},
|
||||
|
||||
// Resizes the canvasPreview to 0x0, essentially freeing its memory.
|
||||
// updateCanvasPreview() will detect the size mismatch as a resize event
|
||||
// the next time it is called.
|
||||
resetCanvasPreview: function () {
|
||||
this.canvasPreview.width = 0;
|
||||
this.canvasPreview.height = 0;
|
||||
},
|
||||
|
||||
// Updates the controller's canvas with the parts of the <browser> that need
|
||||
// to be redrawn.
|
||||
updateCanvasPreview: function () {
|
||||
let win = this.linkedBrowser.contentWindow;
|
||||
let bx = this.linkedBrowser.boxObject;
|
||||
// Check for resize
|
||||
if (bx.width != this.canvasPreview.width ||
|
||||
bx.height != this.canvasPreview.height) {
|
||||
// Invalidate the entire area and repaint
|
||||
this.onTabPaint({left:0, top:0, width:bx.width, height:bx.height});
|
||||
this.canvasPreview.width = bx.width;
|
||||
this.canvasPreview.height = bx.height;
|
||||
}
|
||||
|
||||
// Draw dirty regions
|
||||
let ctx = this.canvasPreview.getContext("2d");
|
||||
let flags = this.canvasPreviewFlags;
|
||||
// width/height are occasionally bogus and too large for drawWindow
|
||||
// so we clip to the canvas region
|
||||
this.dirtyRegion.intersectRect(0, 0, bx.width, bx.height);
|
||||
this.dirtyRects.forEach(function (r) {
|
||||
let x = r.x;
|
||||
let y = r.y;
|
||||
let width = r.width;
|
||||
let height = r.height;
|
||||
ctx.save();
|
||||
ctx.translate(x, y);
|
||||
ctx.drawWindow(win, x, y, width, height, "white", flags);
|
||||
ctx.restore();
|
||||
});
|
||||
this.dirtyRegion.setToRect(0,0,0,0);
|
||||
|
||||
// If we're updating the canvas, then we're in the middle of a peek so
|
||||
// don't discard the cache of previews.
|
||||
AeroPeek.resetCacheTimer();
|
||||
},
|
||||
|
||||
onTabPaint: function (rect) {
|
||||
// Ignore spurious dirty rects
|
||||
if (!rect.width || !rect.height)
|
||||
return;
|
||||
|
||||
let r = { x: Math.floor(rect.left),
|
||||
y: Math.floor(rect.top),
|
||||
width: Math.ceil(rect.width),
|
||||
height: Math.ceil(rect.height)
|
||||
};
|
||||
this.dirtyRegion.unionRect(r.x, r.y, r.width, r.height);
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsITaskbarPreviewController
|
||||
|
||||
get width() {
|
||||
return this.win.width;
|
||||
},
|
||||
|
||||
get height() {
|
||||
return this.win.height;
|
||||
},
|
||||
|
||||
get thumbnailAspectRatio() {
|
||||
let boxObject = this.tab.linkedBrowser.boxObject;
|
||||
// Avoid returning 0
|
||||
let tabWidth = boxObject.width || 1;
|
||||
// Avoid divide by 0
|
||||
let tabHeight = boxObject.height || 1;
|
||||
return tabWidth / tabHeight;
|
||||
},
|
||||
|
||||
drawPreview: function (ctx) {
|
||||
let self = this;
|
||||
this.win.tabbrowser.previewTab(this.tab, function () self.previewTabCallback(ctx));
|
||||
|
||||
// We want a frame drawn around the preview
|
||||
return true;
|
||||
},
|
||||
|
||||
previewTabCallback: function (ctx) {
|
||||
let width = this.win.width;
|
||||
let height = this.win.height;
|
||||
// Draw our toplevel window
|
||||
ctx.drawWindow(this.win.win, 0, 0, width, height, "transparent");
|
||||
|
||||
// Compositor, where art thou?
|
||||
// Draw the tab content on top of the toplevel window
|
||||
this.updateCanvasPreview();
|
||||
|
||||
let boxObject = this.linkedBrowser.boxObject;
|
||||
ctx.translate(boxObject.x, boxObject.y);
|
||||
ctx.drawImage(this.canvasPreview, 0, 0);
|
||||
},
|
||||
|
||||
drawThumbnail: function (ctx, width, height) {
|
||||
this.updateCanvasPreview();
|
||||
|
||||
let scale = width/this.linkedBrowser.boxObject.width;
|
||||
ctx.scale(scale, scale);
|
||||
ctx.drawImage(this.canvasPreview, 0, 0);
|
||||
|
||||
// Don't draw a frame around the thumbnail
|
||||
return false;
|
||||
},
|
||||
|
||||
onClose: function () {
|
||||
this.win.tabbrowser.removeTab(this.tab);
|
||||
},
|
||||
|
||||
onActivate: function () {
|
||||
this.win.tabbrowser.selectedTab = this.tab;
|
||||
|
||||
// Accept activation - this will restore the browser window
|
||||
// if it's minimized
|
||||
return true;
|
||||
},
|
||||
|
||||
//// nsIDOMEventListener
|
||||
handleEvent: function (evt) {
|
||||
switch (evt.type) {
|
||||
case "MozAfterPaint":
|
||||
if (evt.originalTarget === this.linkedBrowser.contentWindow) {
|
||||
let clientRects = evt.clientRects;
|
||||
let length = clientRects.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
let r = clientRects.item(i);
|
||||
this.onTabPaint(r);
|
||||
}
|
||||
}
|
||||
let preview = this.preview;
|
||||
if (preview.visible)
|
||||
preview.invalidate();
|
||||
break;
|
||||
case "pageshow":
|
||||
case "DOMTitleChanged":
|
||||
// The tab's label is sometimes empty when dragging tabs between windows
|
||||
// so we force the tab title to be updated (see bug 520579)
|
||||
this.win.tabbrowser.setTabTitle(this.tab);
|
||||
let title = this.tab.label;
|
||||
this.preview.title = title;
|
||||
this.preview.tooltip = title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(PreviewController.prototype, "canvasPreviewFlags",
|
||||
function () { let canvasInterface = Ci.nsIDOMCanvasRenderingContext2D;
|
||||
return canvasInterface.DRAWWINDOW_DRAW_VIEW
|
||||
| canvasInterface.DRAWWINDOW_DRAW_CARET
|
||||
| canvasInterface.DRAWWINDOW_DO_NOT_FLUSH;
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// TabWindow
|
||||
|
||||
/*
|
||||
* This class monitors a browser window for changes to its tabs
|
||||
*
|
||||
* @param win
|
||||
* The nsIDOMWindow browser window
|
||||
*/
|
||||
function TabWindow(win) {
|
||||
this.win = win;
|
||||
this.tabbrowser = win.gBrowser;
|
||||
|
||||
this.previews = [];
|
||||
|
||||
for (let i = 0; i < this.events.length; i++)
|
||||
this.tabbrowser.tabContainer.addEventListener(this.events[i], this, false);
|
||||
this.tabbrowser.addTabsProgressListener(this);
|
||||
|
||||
|
||||
AeroPeek.windows.push(this);
|
||||
let tabs = this.tabbrowser.mTabs;
|
||||
for (let i = 0; i < tabs.length; i++)
|
||||
this.newTab(tabs[i]);
|
||||
|
||||
this.updateTabOrdering();
|
||||
AeroPeek.checkPreviewCount();
|
||||
}
|
||||
|
||||
TabWindow.prototype = {
|
||||
_enabled: false,
|
||||
events: ["TabOpen", "TabClose", "TabSelect", "TabMove"],
|
||||
|
||||
destroy: function () {
|
||||
this._destroying = true;
|
||||
|
||||
let tabs = this.tabbrowser.mTabs;
|
||||
|
||||
for (let i = 0; i < this.events.length; i++)
|
||||
this.tabbrowser.tabContainer.removeEventListener(this.events[i], this, false);
|
||||
|
||||
for (let i = 0; i < tabs.length; i++)
|
||||
this.removeTab(tabs[i]);
|
||||
|
||||
let idx = AeroPeek.windows.indexOf(this.win.gTaskbarTabGroup);
|
||||
AeroPeek.windows.splice(idx, 1);
|
||||
AeroPeek.checkPreviewCount();
|
||||
},
|
||||
|
||||
get width () {
|
||||
return this.win.innerWidth;
|
||||
},
|
||||
get height () {
|
||||
return this.win.innerHeight;
|
||||
},
|
||||
|
||||
// Invoked when the given tab is added to this window
|
||||
newTab: function (tab) {
|
||||
let controller = new PreviewController(this, tab);
|
||||
let preview = AeroPeek.taskbar.createTaskbarTabPreview(this.tabbrowser.docShell, controller);
|
||||
preview.title = tab.label;
|
||||
preview.tooltip = tab.label;
|
||||
preview.visible = AeroPeek.enabled;
|
||||
preview.active = this.tabbrowser.selectedTab == tab;
|
||||
// Grab the default favicon
|
||||
preview.icon = getFaviconAsImage(null);
|
||||
|
||||
this.previews.splice(tab._tPos, 0, preview);
|
||||
AeroPeek.addPreview(preview);
|
||||
},
|
||||
|
||||
// Invoked when the given tab is closed
|
||||
removeTab: function (tab) {
|
||||
let preview = this.previewFromTab(tab);
|
||||
preview.active = false;
|
||||
preview.visible = false;
|
||||
preview.move(null);
|
||||
preview.controller.wrappedJSObject.destroy();
|
||||
|
||||
// We don't want to splice from the array if the tabs aren't being removed
|
||||
// from the tab bar as well (as is the case when the window closes).
|
||||
if (!this._destroying)
|
||||
this.previews.splice(tab._tPos, 1);
|
||||
AeroPeek.removePreview(preview);
|
||||
},
|
||||
|
||||
get enabled () {
|
||||
return this._enabled;
|
||||
},
|
||||
|
||||
set enabled (enable) {
|
||||
this._enabled = enable;
|
||||
// Because making a tab visible requires that the tab it is next to be
|
||||
// visible, it is far simpler to unset the 'next' tab and recreate them all
|
||||
// at once.
|
||||
this.previews.forEach(function (preview) {
|
||||
preview.move(null);
|
||||
preview.visible = enable;
|
||||
});
|
||||
this.updateTabOrdering();
|
||||
},
|
||||
|
||||
previewFromTab: function (tab) {
|
||||
return this.previews[tab._tPos];
|
||||
},
|
||||
|
||||
updateTabOrdering: function () {
|
||||
for (let i = 0; i < this.previews.length; i++) {
|
||||
let p = this.previews[i];
|
||||
let next = i == this.previews.length - 1 ? null : this.previews[i+1];
|
||||
p.move(next);
|
||||
}
|
||||
},
|
||||
|
||||
//// nsIDOMEventListener
|
||||
handleEvent: function (evt) {
|
||||
let tab = evt.originalTarget;
|
||||
switch (evt.type) {
|
||||
case "TabOpen":
|
||||
this.newTab(tab);
|
||||
this.updateTabOrdering();
|
||||
break;
|
||||
case "TabClose":
|
||||
this.removeTab(tab);
|
||||
this.updateTabOrdering();
|
||||
break;
|
||||
case "TabSelect":
|
||||
this.previewFromTab(tab).active = true;
|
||||
break;
|
||||
case "TabMove":
|
||||
let oldPos = evt.detail;
|
||||
let newPos = tab._tPos;
|
||||
let preview = this.previews[oldPos];
|
||||
this.previews.splice(oldPos, 1);
|
||||
this.previews.splice(newPos, 0, preview);
|
||||
this.updateTabOrdering();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
//// Browser progress listener
|
||||
onLocationChange: function () {
|
||||
},
|
||||
onProgressChange: function () {
|
||||
},
|
||||
onSecurityChange: function () {
|
||||
},
|
||||
onStateChange: function () {
|
||||
},
|
||||
onStatusChange: function () {
|
||||
},
|
||||
onLinkIconAvailable: function (aBrowser) {
|
||||
let img = getFaviconAsImage(aBrowser.mIconURL);
|
||||
let index = this.tabbrowser.browsers.indexOf(aBrowser);
|
||||
this.previews[index].icon = img;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// AeroPeek
|
||||
|
||||
/*
|
||||
* This object acts as global storage and external interface for this feature.
|
||||
* It maintains the values of the prefs.
|
||||
*/
|
||||
var AeroPeek = {
|
||||
available: false,
|
||||
// Does the pref say we're enabled?
|
||||
_prefenabled: true,
|
||||
|
||||
_enabled: true,
|
||||
|
||||
// nsITaskbarTabPreview array
|
||||
previews: [],
|
||||
|
||||
// TabWindow array
|
||||
windows: [],
|
||||
|
||||
// nsIWinTaskbar service
|
||||
taskbar: null,
|
||||
|
||||
// Maximum number of previews
|
||||
maxpreviews: 20,
|
||||
|
||||
// Length of time in seconds that previews are cached
|
||||
cacheLifespan: 20,
|
||||
|
||||
initialize: function () {
|
||||
if (!(WINTASKBAR_CONTRACTID in Cc))
|
||||
return;
|
||||
this.taskbar = Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar);
|
||||
this.available = this.taskbar.available;
|
||||
if (!this.available)
|
||||
return;
|
||||
|
||||
this.prefs.addObserver(TOGGLE_PREF_NAME, this, false);
|
||||
this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, false);
|
||||
this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, false);
|
||||
|
||||
this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME);
|
||||
|
||||
this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
|
||||
|
||||
this.enabled = this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
|
||||
},
|
||||
|
||||
get enabled() {
|
||||
return this._enabled;
|
||||
},
|
||||
|
||||
set enabled(enable) {
|
||||
if (this._enabled == enable)
|
||||
return;
|
||||
|
||||
this._enabled = enable;
|
||||
|
||||
this.windows.forEach(function (win) {
|
||||
win.enabled = enable;
|
||||
});
|
||||
},
|
||||
|
||||
addPreview: function (preview) {
|
||||
this.previews.push(preview);
|
||||
this.checkPreviewCount();
|
||||
},
|
||||
|
||||
removePreview: function (preview) {
|
||||
let idx = this.previews.indexOf(preview);
|
||||
this.previews.splice(idx, 1);
|
||||
this.checkPreviewCount();
|
||||
},
|
||||
|
||||
checkPreviewCount: function () {
|
||||
if (this.previews.length > this.maxpreviews)
|
||||
this.enabled = false;
|
||||
else
|
||||
this.enabled = this._prefenabled;
|
||||
},
|
||||
|
||||
onOpenWindow: function (win) {
|
||||
// This occurs when the taskbar service is not available (xp, vista)
|
||||
if (!this.available)
|
||||
return;
|
||||
|
||||
win.gTaskbarTabGroup = new TabWindow(win);
|
||||
},
|
||||
|
||||
onCloseWindow: function (win) {
|
||||
// This occurs when the taskbar service is not available (xp, vista)
|
||||
if (!this.available)
|
||||
return;
|
||||
|
||||
win.gTaskbarTabGroup.destroy();
|
||||
win.gTaskbarTabGroup = null;
|
||||
},
|
||||
|
||||
resetCacheTimer: function () {
|
||||
this.cacheTimer.cancel();
|
||||
this.cacheTimer.init(this, 1000*this.cacheLifespan, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
//// nsIObserver
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
if (aData == CACHE_EXPIRATION_TIME_PREF_NAME)
|
||||
break;
|
||||
|
||||
if (aData == TOGGLE_PREF_NAME)
|
||||
this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
|
||||
else if (aData == DISABLE_THRESHOLD_PREF_NAME)
|
||||
this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
|
||||
// Might need to enable/disable ourselves
|
||||
this.checkPreviewCount();
|
||||
break;
|
||||
case "timer-callback":
|
||||
this.previews.forEach(function (preview) {
|
||||
let controller = preview.controller.wrappedJSObject;
|
||||
controller.resetCanvasPreview();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(AeroPeek, "cacheTimer", function ()
|
||||
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(AeroPeek, "prefs",
|
||||
"@mozilla.org/preferences-service;1",
|
||||
"nsIPrefBranch2");
|
||||
|
||||
AeroPeek.initialize();
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Rob Arnold <robarnold@cmu.edu>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of 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 *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = browser/components/wintaskbar/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_FILES = browser_taskbar_preview.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
function test() {
|
||||
var isWin7OrHigher = false;
|
||||
try {
|
||||
let version = Cc["@mozilla.org/system-info;1"]
|
||||
.getService(Ci.nsIPropertyBag2)
|
||||
.getProperty("version");
|
||||
isWin7OrHigher = (parseFloat(version) >= 6.1);
|
||||
} catch (ex) { }
|
||||
|
||||
is(!!Win7Features, isWin7OrHigher, "Win7Features available when it should be");
|
||||
if (!isWin7OrHigher)
|
||||
return;
|
||||
|
||||
let temp = {};
|
||||
Cu.import("resource://gre/modules/WindowsPreviewPerTab.jsm", temp);
|
||||
let AeroPeek = temp.AeroPeek;
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gPrefService.setBoolPref("aeropeek.enable", true);
|
||||
|
||||
is(1, AeroPeek.windows.length, "Got the expected number of windows");
|
||||
|
||||
checkPreviews(1, "Browser starts with one preview");
|
||||
|
||||
gBrowser.addTab();
|
||||
gBrowser.addTab();
|
||||
gBrowser.addTab();
|
||||
|
||||
checkPreviews(4, "Correct number of previews after adding");
|
||||
|
||||
for each (let preview in AeroPeek.previews)
|
||||
ok(preview.visible, "Preview is shown as expected");
|
||||
|
||||
gPrefService.setBoolPref("aeropeek.enable", false);
|
||||
checkPreviews(4, "Previews are unchanged when disabling");
|
||||
|
||||
for each (let preview in AeroPeek.previews)
|
||||
ok(!preview.visible, "Preview is not shown as expected after disabling");
|
||||
|
||||
gPrefService.setBoolPref("aeropeek.enable", true);
|
||||
checkPreviews(4, "Previews are unchanged when re-enabling");
|
||||
for each (let preview in AeroPeek.previews)
|
||||
ok(preview.visible, "Preview is shown as expected after re-enabling");
|
||||
|
||||
[1,2,3,4].forEach(function (idx) {
|
||||
gBrowser.selectedTab = gBrowser.mTabs[idx];
|
||||
ok(checkSelectedTab(), "Current tab is correctly selected");
|
||||
});
|
||||
|
||||
let currentSelectedTab = gBrowser.selectedTab;
|
||||
for each (let idx in [1,2,3,4]) {
|
||||
let preview = getPreviewForTab(gBrowser.mTabs[0]);
|
||||
let canvas = createThumbnailSurface(preview);
|
||||
let ctx = canvas.getContext("2d");
|
||||
preview.controller.drawThumbnail(ctx, canvas.width, canvas.height);
|
||||
ok(currentSelectedTab == gBrowser.selectedTab, "Drawing thumbnail does not change selection");
|
||||
canvas = getCanvas(preview.controller.width, preview.controller.height);
|
||||
ctx = canvas.getContext("2d");
|
||||
preview.controller.drawPreview(ctx);
|
||||
ok(currentSelectedTab == gBrowser.selectedTab, "Drawing preview does not change selection");
|
||||
}
|
||||
|
||||
// Close #4
|
||||
getPreviewForTab(gBrowser.selectedTab).controller.onClose();
|
||||
checkPreviews(3, "Expected number of previews after closing selected tab via controller");
|
||||
ok(gBrowser.mTabs.length == 3, "Successfully closed a tab");
|
||||
|
||||
// Select #1
|
||||
ok(getPreviewForTab(gBrowser.mTabs[0]).controller.onActivate(), "Activation was accepted");
|
||||
ok(gBrowser.mTabs[0] == gBrowser.selectedTab, "Correct tab was selected");
|
||||
checkSelectedTab();
|
||||
|
||||
// Remove #3 (non active)
|
||||
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
|
||||
checkPreviews(2, "Expected number of previews after closing unselected via browser");
|
||||
|
||||
// Remove #1 (active)
|
||||
gBrowser.removeTab(gBrowser.tabContainer.firstChild);
|
||||
checkPreviews(1, "Expected number of previews after closing selected tab via browser");
|
||||
|
||||
// Add a new tab
|
||||
gBrowser.addTab();
|
||||
checkPreviews(2);
|
||||
// Check default selection
|
||||
checkSelectedTab();
|
||||
|
||||
// Change selection
|
||||
gBrowser.selectedTab = gBrowser.mTabs[0];
|
||||
checkSelectedTab();
|
||||
// Close nonselected tab via controller
|
||||
getPreviewForTab(gBrowser.mTabs[1]).controller.onClose();
|
||||
checkPreviews(1);
|
||||
|
||||
gPrefService.clearUserPref("aeropeek.enable");
|
||||
|
||||
finish();
|
||||
|
||||
function checkPreviews(aPreviews, msg) {
|
||||
let nPreviews = AeroPeek.previews.length;
|
||||
is(aPreviews, gBrowser.mTabs.length, "Browser has expected number of tabs");
|
||||
is(nPreviews, gBrowser.mTabs.length, "Browser has one preview per tab");
|
||||
is(nPreviews, aPreviews, msg || "Got expected number of previews");
|
||||
}
|
||||
|
||||
function getPreviewForTab(tab)
|
||||
window.gTaskbarTabGroup.previewFromTab(tab);
|
||||
|
||||
function checkSelectedTab()
|
||||
getPreviewForTab(gBrowser.selectedTab).active;
|
||||
|
||||
function isTabSelected(idx)
|
||||
gBrowser.selectedTab == gBrowser.mTabs[idx];
|
||||
|
||||
function createThumbnailSurface(p) {
|
||||
let thumbnailWidth = 200,
|
||||
thumbnailHeight = 120;
|
||||
let ratio = p.controller.thumbnailAspectRatio;
|
||||
|
||||
if (thumbnailWidth/thumbnailHeight > ratio)
|
||||
thumbnailWidth = thumbnailHeight * ratio;
|
||||
else
|
||||
thumbnailHeight = thumbnailWidth / ratio;
|
||||
|
||||
return getCanvas(thumbnailWidth, thumbnailHeight);
|
||||
}
|
||||
|
||||
function getCanvas(width, height) {
|
||||
let win = window.QueryInterface(Ci.nsIDOMWindowInternal);
|
||||
let doc = win.document;
|
||||
let canvas = doc.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
return canvas;
|
||||
}
|
||||
}
|
|
@ -40,11 +40,7 @@
|
|||
#endif
|
||||
|
||||
[xpcom]
|
||||
#ifdef XP_WIN32
|
||||
@BINPATH@/js3250.dll
|
||||
#else
|
||||
@BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
|
||||
#endif
|
||||
@BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
|
||||
@BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
|
||||
@BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
|
||||
|
@ -177,7 +173,6 @@
|
|||
@BINPATH@/components/inspector.xpt
|
||||
@BINPATH@/components/intl.xpt
|
||||
@BINPATH@/components/jar.xpt
|
||||
@BINPATH@/components/jsctypes.xpt
|
||||
@BINPATH@/components/jsdservice.xpt
|
||||
@BINPATH@/components/layout_base.xpt
|
||||
#ifdef NS_PRINTING
|
||||
|
|
|
@ -636,6 +636,12 @@ plugins/Default Plugin.plugin/Contents/MacOS/Default Plugin
|
|||
plugins/Default Plugin.plugin/Contents/PkgInfo
|
||||
plugins/Default Plugin.plugin/Contents/Resources/Default Plugin.rsrc
|
||||
plugins/Default Plugin.plugin/Contents/Resources/English.lproj/InfoPlist.strings
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/Info.plist
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/MacOS/PrintPDE
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/Localizable.strings
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/classes.nib
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/info.nib
|
||||
../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/objects.xib
|
||||
res/cursors/CVS/Entries
|
||||
res/cursors/CVS/Repository
|
||||
res/cursors/CVS/Root
|
||||
|
@ -812,5 +818,8 @@ chrome.manifest
|
|||
install.rdf
|
||||
@DLL_PREFIX@jsj@DLL_SUFFIX@
|
||||
#ifdef XP_WIN
|
||||
js3250.dll
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
components/brwsrcmp.dll
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,12 @@ lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
|
|||
lwthemeInstallRequest.allowButton=Allow
|
||||
lwthemeInstallRequest.allowButton.accesskey=a
|
||||
|
||||
lwthemePostInstallNotification.message=A new theme has been installed.
|
||||
lwthemePostInstallNotification.undoButton=Undo
|
||||
lwthemePostInstallNotification.undoButton.accesskey=U
|
||||
lwthemePostInstallNotification.manageButton=Manage Themes…
|
||||
lwthemePostInstallNotification.manageButton.accesskey=M
|
||||
|
||||
popupWarning=%S prevented this site from opening a pop-up window.
|
||||
popupWarningMultiple=%S prevented this site from opening %S pop-up windows.
|
||||
popupWarningButton=Options
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
taskbar.tasks.newTab.label=Open new tab
|
||||
taskbar.tasks.newTab.description=Open a new browser tab.
|
||||
taskbar.tasks.newWindow.label=Open new window
|
||||
taskbar.tasks.newWindow.description=Open a new browser window.
|
||||
taskbar.frequent.label=Frequent
|
||||
taskbar.recent.label=Recent
|
|
@ -28,6 +28,7 @@
|
|||
locale/browser/shellservice.properties (%chrome/browser/shellservice.properties)
|
||||
locale/browser/tabbrowser.dtd (%chrome/browser/tabbrowser.dtd)
|
||||
locale/browser/tabbrowser.properties (%chrome/browser/tabbrowser.properties)
|
||||
locale/browser/taskbar.properties (%chrome/browser/taskbar.properties)
|
||||
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
|
||||
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
|
||||
locale/browser/places/editBookmarkOverlay.dtd (%chrome/browser/places/editBookmarkOverlay.dtd)
|
||||
|
|
|
@ -1,55 +1 @@
|
|||
af
|
||||
ar
|
||||
be
|
||||
bg
|
||||
bn-IN
|
||||
ca
|
||||
cs
|
||||
cy
|
||||
de
|
||||
el
|
||||
en-GB
|
||||
en-US
|
||||
eo
|
||||
es-AR
|
||||
es-ES
|
||||
et
|
||||
eu
|
||||
fi
|
||||
fr
|
||||
fy-NL
|
||||
ga-IE
|
||||
gu-IN
|
||||
he
|
||||
hi-IN
|
||||
hu
|
||||
id
|
||||
is
|
||||
it
|
||||
ja linux win32
|
||||
ja-JP-mac osx
|
||||
ka
|
||||
kn
|
||||
ko
|
||||
lt
|
||||
lv
|
||||
mr
|
||||
nb-NO
|
||||
nl
|
||||
nn-NO
|
||||
pa-IN
|
||||
pl
|
||||
pt-BR
|
||||
pt-PT
|
||||
ro
|
||||
ru
|
||||
si
|
||||
sk
|
||||
sl
|
||||
sq
|
||||
sv-SE
|
||||
te
|
||||
tr
|
||||
uk
|
||||
zh-CN
|
||||
zh-TW
|
||||
|
|
|
@ -69,6 +69,7 @@ browser/components/sidebar/src/Makefile
|
|||
browser/components/shell/Makefile
|
||||
browser/components/shell/public/Makefile
|
||||
browser/components/shell/src/Makefile
|
||||
browser/components/wintaskbar/Makefile
|
||||
browser/fuel/Makefile
|
||||
browser/fuel/public/Makefile
|
||||
browser/fuel/src/Makefile
|
||||
|
@ -105,6 +106,7 @@ if [ "$ENABLE_TESTS" ]; then
|
|||
browser/components/privatebrowsing/test/Makefile
|
||||
browser/components/privatebrowsing/test/browser/Makefile
|
||||
browser/components/safebrowsing/content/test/Makefile
|
||||
browser/components/wintaskbar/test/Makefile
|
||||
browser/fuel/test/Makefile
|
||||
"
|
||||
fi
|
||||
|
|
Двоичные данные
browser/themes/pinstripe/browser/Search-bar.png
Двоичные данные
browser/themes/pinstripe/browser/Search-bar.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 251 B |
|
@ -60,7 +60,9 @@
|
|||
#nav-bar:-moz-lwtheme {
|
||||
-moz-appearance: none !important;
|
||||
background: none !important;
|
||||
border-style: none !important;
|
||||
/* Switching to a lightweight theme shouldn't move the content area,
|
||||
so avoid changing border widths here. */
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.tabbrowser-strip:-moz-lwtheme,
|
||||
|
|
|
@ -43,7 +43,6 @@ browser.jar:
|
|||
skin/classic/browser/searchbar.css
|
||||
skin/classic/browser/Search.png
|
||||
skin/classic/browser/Search-addengines.png
|
||||
skin/classic/browser/Search-bar.png
|
||||
skin/classic/browser/section_collapsed.png
|
||||
skin/classic/browser/section_expanded.png
|
||||
skin/classic/browser/Secure-Glyph-White.png
|
||||
|
|
|
@ -256,29 +256,6 @@ window:not([active="true"]) #placesList > treechildren::-moz-tree-row(selected)
|
|||
border: 0px;
|
||||
}
|
||||
|
||||
.filterList {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
border: 0px;
|
||||
margin: 2px;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://browser/skin/Search-bar.png");
|
||||
-moz-user-focus: ignore;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.filterList .button-box {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.filterList .button-menu-dropmarker {
|
||||
margin: 9px -3px -4px 8px;
|
||||
}
|
||||
|
||||
/* Scope Bar */
|
||||
|
||||
#advancedSearch > hbox,
|
||||
|
|
|
@ -413,6 +413,8 @@ def environment(env = None, xrePath = DIST_BIN, crashreporter = True):
|
|||
envVar = "LD_LIBRARY_PATH"
|
||||
if IS_MAC:
|
||||
envVar = "DYLD_LIBRARY_PATH"
|
||||
else: # unixish
|
||||
env['MOZILLA_FIVE_HOME'] = xrePath
|
||||
if envVar in env:
|
||||
ldLibraryPath = ldLibraryPath + ":" + env[envVar]
|
||||
env[envVar] = ldLibraryPath
|
||||
|
@ -422,7 +424,7 @@ def environment(env = None, xrePath = DIST_BIN, crashreporter = True):
|
|||
if crashreporter:
|
||||
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
||||
env['MOZ_CRASHREPORTER'] = '1'
|
||||
|
||||
env['GNOME_DISABLE_CRASH_DIALOG'] = "1"
|
||||
return env
|
||||
|
||||
|
||||
|
@ -438,6 +440,7 @@ def runApp(testURL, env, app, profileDir, extraArgs,
|
|||
|
||||
# copy env so we don't munge the caller's environment
|
||||
env = dict(env);
|
||||
env["NO_EM_RESTART"] = "1"
|
||||
|
||||
if IS_TEST_BUILD and runSSLTunnel:
|
||||
# create certificate database for the profile
|
||||
|
|
|
@ -72,16 +72,10 @@ if __name__ == '__main__':
|
|||
t.start()
|
||||
|
||||
automation.initializeProfile(PROFILE_DIRECTORY)
|
||||
browserEnv = dict(os.environ)
|
||||
browserEnv = automation.environment()
|
||||
|
||||
browserEnv["NO_EM_RESTART"] = "1"
|
||||
if not "XPCOM_DEBUG_BREAK" in browserEnv:
|
||||
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
|
||||
if automation.UNIXISH:
|
||||
browserEnv["LD_LIBRARY_PATH"] = os.path.join(SCRIPT_DIR, DIST_BIN)
|
||||
browserEnv["MOZILLA_FIVE_HOME"] = os.path.join(SCRIPT_DIR, DIST_BIN)
|
||||
browserEnv["GNOME_DISABLE_CRASH_DIALOG"] = "1"
|
||||
|
||||
url = "http://localhost:%d/bloatcycle.html" % PORT
|
||||
appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
|
||||
status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY,
|
||||
|
|
|
@ -63,15 +63,8 @@ if __name__ == '__main__':
|
|||
t.start()
|
||||
|
||||
automation.initializeProfile(PROFILE_DIRECTORY)
|
||||
browserEnv = dict(os.environ)
|
||||
|
||||
# These variables are necessary for correct application startup; change
|
||||
# via the commandline at your own risk.
|
||||
browserEnv["NO_EM_RESTART"] = "1"
|
||||
browserEnv = automation.environment()
|
||||
browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
|
||||
if automation.UNIXISH:
|
||||
browserEnv["LD_LIBRARY_PATH"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
|
||||
browserEnv["MOZILLA_FIVE_HOME"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
|
||||
|
||||
url = "http://localhost:%d/index.html" % PORT
|
||||
appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
|
||||
|
|
|
@ -89,7 +89,6 @@ MOZ_X11 = @MOZ_X11@
|
|||
MOZ_PANGO = @MOZ_PANGO@
|
||||
|
||||
MOZ_CORETEXT = @MOZ_CORETEXT@
|
||||
MOZ_COCOA_PRINTING = @MOZ_COCOA_PRINTING@
|
||||
|
||||
MOZ_JS_LIBS = @MOZ_JS_LIBS@
|
||||
|
||||
|
|
|
@ -707,18 +707,6 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
# Flags needed to link against the component library
|
||||
ifdef MOZ_COMPONENTLIB
|
||||
MOZ_COMPONENTLIB_EXTRA_DSO_LIBS = mozcomps
|
||||
|
||||
# Tell the linker where NSS is, if we're building crypto
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
ifeq (,$(findstring crypto,$(MOZ_META_COMPONENTS)))
|
||||
MOZ_COMPONENTLIB_EXTRA_LIBS = $(foreach library, $(patsubst -l%, $(LIB_PREFIX)%$(DLL_SUFFIX), $(filter -l%, $(NSS_LIBS))), -dylib_file @executable_path/$(library):$(DIST)/bin/$(library))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# If we're building a component on MSVC, we don't want to generate an
|
||||
# import lib, because that import lib will collide with the name of a
|
||||
# static version of the same library.
|
||||
|
@ -758,7 +746,7 @@ else
|
|||
ifeq (OS2,$(CROSS_COMPILE)$(OS_ARCH))
|
||||
NSINSTALL = $(MOZ_TOOLS_DIR)/nsinstall
|
||||
else
|
||||
NSINSTALL = $(CONFIG_TOOLS)/nsinstall
|
||||
NSINSTALL = $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX)
|
||||
endif # OS2
|
||||
endif # NSINSTALL_BIN
|
||||
|
||||
|
@ -786,7 +774,7 @@ endif # WINNT/OS2
|
|||
|
||||
ifeq (,$(filter-out WINCE,$(OS_ARCH)))
|
||||
NSINSTALL = $(CYGWIN_WRAPPER) nsinstall
|
||||
INSTALL = $(CYGWIN_WRAPPER) nsinstall
|
||||
INSTALL = $(CYGWIN_WRAPPER) nsinstall
|
||||
endif
|
||||
|
||||
# Use nsinstall in copy mode to install files on the system
|
||||
|
|
|
@ -230,9 +230,11 @@ endif # ENABLE_TESTS
|
|||
ifndef LIBRARY
|
||||
ifdef STATIC_LIBRARY_NAME
|
||||
ifeq (OS2,$(OS_ARCH))
|
||||
ifdef SHORT_LIBNAME
|
||||
STATIC_LIBRARY_NAME := $(SHORT_LIBNAME)
|
||||
SHARED_LIBRARY_NAME := $(SHORT_LIBNAME)
|
||||
endif
|
||||
endif
|
||||
LIBRARY := $(LIB_PREFIX)$(STATIC_LIBRARY_NAME).$(LIB_SUFFIX)
|
||||
endif # STATIC_LIBRARY_NAME
|
||||
endif # LIBRARY
|
||||
|
|
92
configure.in
92
configure.in
|
@ -42,6 +42,8 @@ dnl Mac OS X 10.4 support
|
|||
dnl Giorgio Maone <g.maone@informaction.com>
|
||||
dnl MSVC l10n compatible version check
|
||||
dnl Ben Turner <mozilla@songbirdnest.com>
|
||||
dnl Windows x64 support
|
||||
dnl Makoto Kato <m_kato@ga2.so-net.ne.jp>
|
||||
dnl
|
||||
dnl Alternatively, the contents of this file may be used under the terms of
|
||||
dnl either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -192,7 +194,16 @@ case "$target" in
|
|||
if test -z "$CPP"; then CPP="cl -E -nologo"; fi
|
||||
if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
|
||||
if test -z "$LD"; then LD=link; fi
|
||||
if test -z "$AS"; then AS=ml; fi
|
||||
if test -z "$AS"; then
|
||||
case "${target_cpu}" in
|
||||
i*86)
|
||||
AS=ml;
|
||||
;;
|
||||
x86_64)
|
||||
AS=ml64;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test -z "$MIDL"; then MIDL=midl; fi
|
||||
;;
|
||||
*-darwin*)
|
||||
|
@ -635,6 +646,9 @@ case "$target" in
|
|||
AC_MSG_RESULT([none needed])
|
||||
fi
|
||||
;;
|
||||
x86_64-*)
|
||||
MIDL_FLAGS="${MIDL_FLAGS} -env x64"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([none needed])
|
||||
;;
|
||||
|
@ -1586,7 +1600,7 @@ AC_LANG_SAVE
|
|||
AC_LANG_C
|
||||
AC_MSG_CHECKING(for 64-bit OS)
|
||||
AC_TRY_COMPILE([$configure_static_assert_macros],
|
||||
[CONFIGURE_STATIC_ASSERT(sizeof(long) == 8)],
|
||||
[CONFIGURE_STATIC_ASSERT(sizeof(void*) == 8)],
|
||||
result="yes", result="no")
|
||||
AC_MSG_RESULT("$result")
|
||||
if test "$result" = "yes"; then
|
||||
|
@ -1653,6 +1667,12 @@ case "$host" in
|
|||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${host_cpu}" in
|
||||
x86_64)
|
||||
HOST_CFLAGS="$HOST_CFLAGS -D_AMD64_"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
*-darwin*)
|
||||
|
@ -2037,7 +2057,7 @@ case "$target" in
|
|||
MOZ_DEBUG_FLAGS='-Zi'
|
||||
MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
|
||||
MOZ_FIX_LINK_PATHS=
|
||||
MOZ_JS_LIBS='$(LIBXUL_DIST)/lib/js$(MOZ_BITS)$(VERSION_NUMBER).lib'
|
||||
MOZ_JS_LIBS='$(LIBXUL_DIST)/lib/mozjs.lib'
|
||||
OBJ_SUFFIX=obj
|
||||
RANLIB='echo not_ranlib'
|
||||
STRIP='echo not_strip'
|
||||
|
@ -2101,7 +2121,7 @@ case "$target" in
|
|||
RCFLAGS='-O coff --use-temp-file'
|
||||
# mingw doesn't require kernel32, user32, and advapi32 explicitly
|
||||
LIBS="$LIBS -lgdi32 -lwinmm -lwsock32"
|
||||
MOZ_JS_LIBS='-L$(LIBXUL_DIST)/lib -ljs$(MOZ_BITS)$(VERSION_NUMBER)'
|
||||
MOZ_JS_LIBS='-L$(LIBXUL_DIST)/lib -lmozjs'
|
||||
MOZ_FIX_LINK_PATHS=
|
||||
DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib -lxpcom -lxpcom_core'
|
||||
XPCOM_FROZEN_LDOPTS='-L$(LIBXUL_DIST)/lib -lxpcom'
|
||||
|
@ -2112,6 +2132,9 @@ case "$target" in
|
|||
HOST_CC='$(CC)'
|
||||
HOST_CXX='$(CXX)'
|
||||
HOST_LD='$(LD)'
|
||||
if test "$AS_BIN"; then
|
||||
AS="$(basename "$AS_BIN")"
|
||||
fi
|
||||
AR='lib -NOLOGO -OUT:"$@"'
|
||||
AR_FLAGS=
|
||||
RANLIB='echo not_ranlib'
|
||||
|
@ -2121,6 +2144,7 @@ case "$target" in
|
|||
UNZIP=unzip
|
||||
DOXYGEN=:
|
||||
GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb'
|
||||
ASM_SUFFIX=asm
|
||||
OBJ_SUFFIX=obj
|
||||
LIB_SUFFIX=lib
|
||||
DLL_PREFIX=
|
||||
|
@ -2141,14 +2165,14 @@ case "$target" in
|
|||
MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
|
||||
WARNINGS_AS_ERRORS='-WX'
|
||||
MOZ_OPTIMIZE_FLAGS='-O1'
|
||||
MOZ_JS_LIBS='$(LIBXUL_DIST)/lib/js$(MOZ_BITS)$(VERSION_NUMBER).lib'
|
||||
MOZ_JS_LIBS='$(LIBXUL_DIST)/lib/mozjs.lib'
|
||||
MOZ_FIX_LINK_PATHS=
|
||||
DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib'
|
||||
XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib'
|
||||
LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib'
|
||||
MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)'
|
||||
if test $_MSC_VER -ge 1400; then
|
||||
LDFLAGS="$LDFLAGS -NXCOMPAT -SAFESEH"
|
||||
LDFLAGS="$LDFLAGS -NXCOMPAT"
|
||||
dnl For profile-guided optimization
|
||||
PROFILE_GEN_CFLAGS="-GL"
|
||||
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
||||
|
@ -2308,7 +2332,7 @@ case "$target" in
|
|||
;;
|
||||
|
||||
*)
|
||||
AC_CHECK_HEADERS(mmintrin.h oleacc.idl)
|
||||
AC_CHECK_HEADERS(oleacc.idl)
|
||||
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
|
@ -2319,6 +2343,14 @@ case "$target" in
|
|||
|
||||
case "$target" in
|
||||
i*86-*)
|
||||
if test "$HAVE_64BIT_OS"; then
|
||||
AC_MSG_ERROR([You are targeting i386 but using the 64-bit compiler.])
|
||||
fi
|
||||
|
||||
if test $_MSC_VER -ge 1400; then
|
||||
LDFLAGS="$LDFLAGS -SAFESEH"
|
||||
fi
|
||||
AC_CHECK_HEADERS(mmintrin.h)
|
||||
AC_DEFINE(_X86_)
|
||||
;;
|
||||
alpha-*)
|
||||
|
@ -2327,10 +2359,17 @@ case "$target" in
|
|||
mips-*)
|
||||
AC_DEFINE(_MIPS_)
|
||||
;;
|
||||
x86_64-*)
|
||||
AC_DEFINE(_AMD64_)
|
||||
;;
|
||||
*)
|
||||
AC_DEFINE(_CPU_ARCH_NOT_DEFINED)
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$HAVE_64BIT_OS"; then
|
||||
AC_DEFINE(_WIN64)
|
||||
fi
|
||||
;;
|
||||
|
||||
*-netbsd*)
|
||||
|
@ -3150,8 +3189,7 @@ case $target in
|
|||
esac
|
||||
|
||||
dnl ========================================================
|
||||
dnl Check whether we can compile code for Core Text and
|
||||
dnl Cocoa printing
|
||||
dnl Check whether we can compile code for Core Text
|
||||
dnl (Mac OS X 10.5 or later)
|
||||
dnl ========================================================
|
||||
case "$target" in
|
||||
|
@ -3159,9 +3197,9 @@ case "$target" in
|
|||
AC_MSG_CHECKING([for Core Text])
|
||||
AC_TRY_COMPILE([#include <ApplicationServices/ApplicationServices.h>],
|
||||
[CTLineRef lineRef;],
|
||||
ac_cv_have_leopard="yes",
|
||||
ac_cv_have_leopard="no")
|
||||
AC_MSG_RESULT([$ac_cv_have_leopard])
|
||||
ac_cv_have_core_text="yes",
|
||||
ac_cv_have_core_text="no")
|
||||
AC_MSG_RESULT([$ac_cv_have_core_text])
|
||||
|
||||
MOZ_CORETEXT=1
|
||||
|
||||
|
@ -3171,30 +3209,15 @@ case "$target" in
|
|||
MOZ_CORETEXT=1)
|
||||
|
||||
if test -n "$MOZ_CORETEXT"; then
|
||||
if test "$ac_cv_have_leopard" = "no"; then
|
||||
if test "$ac_cv_have_core_text" = "no"; then
|
||||
AC_MSG_ERROR([--enable-coretext requires MacOS SDK 10.5 or newer])
|
||||
fi
|
||||
AC_DEFINE(MOZ_CORETEXT)
|
||||
fi
|
||||
|
||||
MOZ_COCOA_PRINTING=1
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(cocoa-printing,
|
||||
[ --disable-cocoa-printing
|
||||
Use a Carbon print dialog instead of a Cocoa one],
|
||||
MOZ_COCOA_PRINTING=,
|
||||
MOZ_COCOA_PRINTING=1)
|
||||
|
||||
if test -n "$MOZ_COCOA_PRINTING"; then
|
||||
if test "$ac_cv_have_leopard" = "no"; then
|
||||
AC_MSG_ERROR([--enable-cocoa-printing requires MacOS SDK 10.5 or newer])
|
||||
fi
|
||||
AC_DEFINE(MOZ_COCOA_PRINTING)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST(MOZ_COCOA_PRINTING)
|
||||
AC_SUBST(MOZ_CORETEXT)
|
||||
|
||||
XLDFLAGS="$X_LIBS"
|
||||
XLIBS="$X_EXTRA_LIBS"
|
||||
|
@ -6511,13 +6534,22 @@ if test "$MOZ_MEMORY"; then
|
|||
WIN32_CRT_SRC_DIR="$VCINSTALLDIR\crt\src"
|
||||
fi
|
||||
fi
|
||||
dnl cpu check
|
||||
case "${target_cpu}" in
|
||||
i*86)
|
||||
_WIN32_CRT_CPU=intel
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([--enable-jemalloc not supported on ${target}])
|
||||
;;
|
||||
esac
|
||||
|
||||
if test ! -d "$WIN32_CRT_SRC_DIR"; then
|
||||
AC_MSG_ERROR([Invalid Win32 CRT source directory: ${WIN32_CRT_SRC_DIR}])
|
||||
fi
|
||||
WIN32_CRT_SRC_DIR=`cd "$WIN32_CRT_SRC_DIR" && pwd -W`
|
||||
_objdir_win=`pwd -W`
|
||||
WIN32_CUSTOM_CRT_DIR="$_objdir_win/memory/jemalloc/crtsrc/build/intel"
|
||||
WIN32_CUSTOM_CRT_DIR="$_objdir_win/memory/jemalloc/crtsrc/build/$_WIN32_CRT_CPU"
|
||||
MOZ_MEMORY_LDFLAGS="-MANIFEST:NO -LIBPATH:\"$WIN32_CUSTOM_CRT_DIR\" -NODEFAULTLIB:msvcrt -NODEFAULTLIB:msvcrtd -NODEFAULTLIB:msvcprt -NODEFAULTLIB:msvcprtd -DEFAULTLIB:mozcrt19 -DEFAULTLIB:mozcpp19"
|
||||
dnl Also pass this to NSPR/NSS
|
||||
DLLFLAGS="$DLLFLAGS $MOZ_MEMORY_LDFLAGS"
|
||||
|
|
|
@ -93,9 +93,11 @@ XPIDLSRCS = \
|
|||
nsIContentPolicy.idl \
|
||||
nsIDocumentEncoder.idl \
|
||||
nsIDOMFile.idl \
|
||||
nsIDOMFileRequest.idl \
|
||||
nsIDOMFileInternal.idl \
|
||||
nsIDOMFileList.idl \
|
||||
nsIDOMFileException.idl \
|
||||
nsIDOMFileError.idl \
|
||||
nsIDOMParser.idl \
|
||||
nsIDOMSerializer.idl \
|
||||
nsISelection2.idl \
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMFileInternal.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIDOMFileError.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -117,4 +118,16 @@ private:
|
|||
nsCOMArray<nsIDOMFile> mFiles;
|
||||
};
|
||||
|
||||
class nsDOMFileError : public nsIDOMFileError
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMFILEERROR
|
||||
|
||||
nsDOMFileError(PRUint16 aErrorCode) : mCode(aErrorCode) {}
|
||||
|
||||
private:
|
||||
PRUint16 mCode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,16 +37,20 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
|
||||
[scriptable, uuid(4a17d83b-424f-43f3-8a7c-430f406921be)]
|
||||
interface nsIDOMFileError;
|
||||
|
||||
[scriptable, uuid(0845E8AE-56BD-4F0E-962A-3B3E92638A0B)]
|
||||
interface nsIDOMFile : nsISupports
|
||||
{
|
||||
//fileName and fileSize are now deprecated attributes
|
||||
readonly attribute DOMString fileName;
|
||||
readonly attribute unsigned long long fileSize;
|
||||
|
||||
DOMString getAsText(in DOMString encoding);
|
||||
// raises(FileException) on retrieval
|
||||
DOMString getAsDataURL();
|
||||
// raises(FileException) on retrieval
|
||||
DOMString getAsBinary();
|
||||
// raises(FileException) on retrieval
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute unsigned long long size;
|
||||
readonly attribute DOMString mediaType;
|
||||
|
||||
DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval
|
||||
DOMString getAsDataURL(); // raises(FileException) on retrieval
|
||||
DOMString getAsBinary(); // raises(FileException) on retrieval
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -15,16 +15,15 @@
|
|||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2000
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Conrad Carlen <ccarlen@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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"),
|
||||
* 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
|
||||
|
@ -36,26 +35,18 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsPrintSessionX_h_
|
||||
#define nsPrintSessionX_h_
|
||||
#include "domstubs.idl"
|
||||
|
||||
#include "nsPrintSession.h"
|
||||
#include "nsIPrintSessionX.h"
|
||||
|
||||
class nsPrintSessionX : public nsPrintSession,
|
||||
public nsIPrintSessionX
|
||||
[scriptable, uuid(4BDAFB64-15E2-49C1-A090-4315A7884A56)]
|
||||
interface nsIDOMFileError : nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPRINTSESSIONX
|
||||
//File error codes
|
||||
const unsigned short NOT_FOUND_ERR = 8;
|
||||
const unsigned short NOT_READABLE_ERR = 24;
|
||||
const unsigned short SECURITY_ERR = 18;
|
||||
const unsigned short ABORT_ERR = 25;
|
||||
const unsigned short ENCODING_ERR = 26;
|
||||
|
||||
nsPrintSessionX();
|
||||
virtual ~nsPrintSessionX();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
protected:
|
||||
PMPrintSession mSession;
|
||||
readonly attribute unsigned short code;
|
||||
};
|
||||
|
||||
#endif // nsPrintSessionX_h_
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -12,8 +12,7 @@
|
|||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
|
@ -21,7 +20,6 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Daniel Veditz <dveditz@netscape.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
|
||||
|
@ -37,24 +35,37 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _zipfile_h
|
||||
#define _zipfile_h
|
||||
/*
|
||||
* This module implements a simple archive extractor for the PKZIP format.
|
||||
*
|
||||
* All functions return a status/error code, and have an opaque hZip argument
|
||||
* that represents an open archive.
|
||||
*
|
||||
* Currently only compression mode 8 (or none) is supported.
|
||||
*/
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
#define ZIP_OK NS_OK
|
||||
#define ZIP_ERR_MEMORY NS_ERROR_OUT_OF_MEMORY
|
||||
#define ZIP_ERR_DISK NS_ERROR_FILE_DISK_FULL
|
||||
#define ZIP_ERR_CORRUPT NS_ERROR_FILE_CORRUPTED
|
||||
#define ZIP_ERR_PARAM NS_ERROR_ILLEGAL_VALUE
|
||||
#define ZIP_ERR_FNF NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
|
||||
#define ZIP_ERR_UNSUPPORTED NS_ERROR_NOT_IMPLEMENTED
|
||||
#define ZIP_ERR_GENERAL NS_ERROR_FAILURE
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMFile;
|
||||
interface nsIDOMFileError;
|
||||
|
||||
#endif /* _zipfile_h */
|
||||
[scriptable, uuid(074FEC26-7FAB-4E05-9E60-EC49E148F5EF)]
|
||||
interface nsIDOMFileRequest : nsISupports
|
||||
{
|
||||
void readAsBinaryString(in nsIDOMFile filedata);
|
||||
void readAsText(in nsIDOMFile filedata, [optional] in DOMString encoding);
|
||||
void readAsDataURL(in nsIDOMFile file);
|
||||
|
||||
void abort();
|
||||
|
||||
const unsigned short INITIAL = 0;
|
||||
const unsigned short LOADING = 1;
|
||||
const unsigned short DONE = 2;
|
||||
readonly attribute unsigned short readyState;
|
||||
|
||||
readonly attribute DOMString response;
|
||||
readonly attribute nsIDOMFileError error;
|
||||
|
||||
// event handler attributes
|
||||
attribute nsIDOMEventListener onloadend;
|
||||
};
|
||||
|
||||
%{ C++
|
||||
#define NS_FILEREQUEST_CID \
|
||||
{0x06aa7c21, 0xfe05, 0x4cf2, \
|
||||
{0xb1, 0xc4, 0x0c, 0x71, 0x26, 0xa4, 0xf7, 0x13}}
|
||||
#define NS_FILEREQUEST_CONTRACTID \
|
||||
"@mozilla.org/files/filerequest;1"
|
||||
%}
|
|
@ -84,6 +84,7 @@ CPPSRCS = \
|
|||
nsDOMAttributeMap.cpp \
|
||||
nsDOMDocumentType.cpp \
|
||||
nsDOMFile.cpp \
|
||||
nsDOMFileRequest.cpp \
|
||||
nsDOMLists.cpp \
|
||||
nsDOMParser.cpp \
|
||||
nsDOMSerializer.cpp \
|
||||
|
|
|
@ -375,13 +375,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseContentList)
|
|||
NS_IMPL_ADDREF_INHERITED(nsContentList, nsBaseContentList)
|
||||
NS_IMPL_RELEASE_INHERITED(nsContentList, nsBaseContentList)
|
||||
|
||||
|
||||
nsISupports *
|
||||
nsContentList::GetParentObject()
|
||||
{
|
||||
return mRootNode;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsContentList::Length(PRBool aDoFlush)
|
||||
{
|
||||
|
|
|
@ -269,7 +269,7 @@ public:
|
|||
virtual nsISupports* GetNamedItem(const nsAString& aName, nsresult* aResult);
|
||||
|
||||
// nsContentList public methods
|
||||
NS_HIDDEN_(nsISupports*) GetParentObject();
|
||||
NS_HIDDEN_(nsINode*) GetParentObject() { return mRootNode; }
|
||||
NS_HIDDEN_(PRUint32) Length(PRBool aDoFlush);
|
||||
NS_HIDDEN_(nsIContent*) Item(PRUint32 aIndex, PRBool aDoFlush);
|
||||
NS_HIDDEN_(nsIContent*) NamedItem(const nsAString& aName, PRBool aDoFlush);
|
||||
|
|
|
@ -357,11 +357,6 @@ nsContentSink::ScriptAvailable(nsresult aResult,
|
|||
|
||||
// Check if this is the element we were waiting for
|
||||
if (count == 0 || aElement != mScriptElements[count - 1]) {
|
||||
if (mDidGetReadyToCallDidBuildModelCall &&
|
||||
!mScriptLoader->HasPendingOrCurrentScripts() &&
|
||||
mParser && mParser->IsParserEnabled()) {
|
||||
ContinueInterruptedParsingAsync();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -404,11 +399,6 @@ nsContentSink::ScriptEvaluated(nsresult aResult,
|
|||
// Check if this is the element we were waiting for
|
||||
PRInt32 count = mScriptElements.Count();
|
||||
if (count == 0 || aElement != mScriptElements[count - 1]) {
|
||||
if (mDidGetReadyToCallDidBuildModelCall &&
|
||||
!mScriptLoader->HasPendingOrCurrentScripts() &&
|
||||
mParser && mParser->IsParserEnabled()) {
|
||||
ContinueInterruptedParsingAsync();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1642,8 +1632,16 @@ nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
|
|||
}
|
||||
|
||||
void
|
||||
nsContentSink::DidBuildModelImpl(void)
|
||||
nsContentSink::DidBuildModelImpl(PRBool aTerminated)
|
||||
{
|
||||
if (mDocument && !aTerminated) {
|
||||
mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
|
||||
}
|
||||
|
||||
if (mScriptLoader) {
|
||||
mScriptLoader->ParsingComplete(aTerminated);
|
||||
}
|
||||
|
||||
if (!mDocument->HaveFiredDOMTitleChange()) {
|
||||
mDocument->NotifyPossibleTitleChange(PR_FALSE);
|
||||
}
|
||||
|
@ -1768,26 +1766,6 @@ nsContentSink::ContinueInterruptedParsingAsync()
|
|||
NS_DispatchToCurrentThread(ev);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsContentSink::ReadyToCallDidBuildModelImpl(PRBool aTerminated)
|
||||
{
|
||||
if (!mDidGetReadyToCallDidBuildModelCall) {
|
||||
if (mDocument && !aTerminated) {
|
||||
mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
|
||||
}
|
||||
|
||||
if (mScriptLoader) {
|
||||
mScriptLoader->ParsingComplete(aTerminated);
|
||||
}
|
||||
}
|
||||
|
||||
mDidGetReadyToCallDidBuildModelCall = PR_TRUE;
|
||||
|
||||
// If we're terminated we always want to call DidBuildModel.
|
||||
return aTerminated || !mScriptLoader ||
|
||||
!mScriptLoader->HasPendingOrCurrentScripts();
|
||||
}
|
||||
|
||||
// URIs: action, href, src, longdesc, usemap, cite
|
||||
PRBool
|
||||
IsAttrURI(nsIAtom *aName)
|
||||
|
|
|
@ -133,8 +133,7 @@ class nsContentSink : public nsICSSLoaderObserver,
|
|||
NS_HIDDEN_(nsresult) WillResumeImpl(void);
|
||||
NS_HIDDEN_(nsresult) DidProcessATokenImpl(void);
|
||||
NS_HIDDEN_(void) WillBuildModelImpl(void);
|
||||
NS_HIDDEN_(void) DidBuildModelImpl(void);
|
||||
NS_HIDDEN_(PRBool) ReadyToCallDidBuildModelImpl(PRBool aTerminated);
|
||||
NS_HIDDEN_(void) DidBuildModelImpl(PRBool aTerminated);
|
||||
NS_HIDDEN_(void) DropParserAndPerfHint(void);
|
||||
PRBool IsScriptExecutingImpl();
|
||||
|
||||
|
@ -338,8 +337,6 @@ protected:
|
|||
PRUint8 mDeferredLayoutStart : 1;
|
||||
// If true, we deferred notifications until sheets load
|
||||
PRUint8 mDeferredFlushTags : 1;
|
||||
// If true, we did get a ReadyToCallDidBuildModel call
|
||||
PRUint8 mDidGetReadyToCallDidBuildModelCall : 1;
|
||||
// If false, we're not ourselves a document observer; that means we
|
||||
// shouldn't be performing any more content model notifications,
|
||||
// since we're not longer updating our child counts.
|
||||
|
|
|
@ -93,11 +93,23 @@ DOMFileResult(nsresult rv)
|
|||
NS_IMETHODIMP
|
||||
nsDOMFile::GetFileName(nsAString &aFileName)
|
||||
{
|
||||
return mFile->GetLeafName(aFileName);
|
||||
return GetName(aFileName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetFileSize(PRUint64 *aFileSize)
|
||||
{
|
||||
return GetSize(aFileSize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetName(nsAString &aFileName)
|
||||
{
|
||||
return mFile->GetLeafName(aFileName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetSize(PRUint64 *aFileSize)
|
||||
{
|
||||
PRInt64 fileSize;
|
||||
nsresult rv = mFile->GetFileSize(&fileSize);
|
||||
|
@ -112,6 +124,30 @@ nsDOMFile::GetFileSize(PRUint64 *aFileSize)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetMediaType(nsAString &aMediaType)
|
||||
{
|
||||
if (!mContentType.Length()) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCAutoString mediaType;
|
||||
rv = mimeService->GetTypeFromFile(mFile, mediaType);
|
||||
if (NS_FAILED(rv)) {
|
||||
SetDOMStringToNull(aMediaType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(mediaType, mContentType);
|
||||
}
|
||||
|
||||
aMediaType = mContentType;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult)
|
||||
{
|
||||
|
@ -405,3 +441,21 @@ nsDOMFileList::Item(PRUint32 aIndex, nsIDOMFile **aFile)
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDOMFileError implementation
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMFileError)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileError)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFileError)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileError)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsDOMFileError)
|
||||
NS_IMPL_RELEASE(nsDOMFileError)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileError::GetCode(PRUint16* aCode)
|
||||
{
|
||||
*aCode = mCode;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,737 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozila.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsDOMFileRequest.h"
|
||||
|
||||
#include "nsContentCID.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsICharsetAlias.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsIConverterInputStream.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsIUnicharInputStream.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "prmem.h"
|
||||
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDOMFileInternal.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsLayoutStatics.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
|
||||
#define LOAD_STR "load"
|
||||
#define ERROR_STR "error"
|
||||
#define ABORT_STR "abort"
|
||||
#define LOADSTART_STR "loadstart"
|
||||
#define PROGRESS_STR "progress"
|
||||
#define UPLOADPROGRESS_STR "uploadprogress"
|
||||
#define LOADEND_STR "loadend"
|
||||
|
||||
#define NS_PROGRESS_EVENT_INTERVAL 50
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileRequest,
|
||||
nsXHREventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadEndListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressNotifier)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileRequest,
|
||||
nsXHREventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadEndListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressNotifier)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMFileRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFileRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(FileRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsDOMFileRequest, nsXHREventTarget)
|
||||
NS_IMPL_RELEASE_INHERITED(nsDOMFileRequest, nsXHREventTarget)
|
||||
|
||||
static const PRUint32 FILE_AS_BINARY = 1;
|
||||
static const PRUint32 FILE_AS_TEXT = 2;
|
||||
static const PRUint32 FILE_AS_DATAURL = 3;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::GetOnloadend(nsIDOMEventListener** aOnloadend)
|
||||
{
|
||||
return GetInnerEventListener(mOnLoadEndListener, aOnloadend);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::SetOnloadend(nsIDOMEventListener* aOnloadend)
|
||||
{
|
||||
return RemoveAddEventListener(NS_LITERAL_STRING(LOADEND_STR),
|
||||
mOnLoadEndListener, aOnloadend);
|
||||
}
|
||||
|
||||
//nsICharsetDetectionObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::Notify(const char *aCharset, nsDetectionConfident aConf)
|
||||
{
|
||||
CopyASCIItoUTF16(aCharset, mCharset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//nsDOMFileRequest constructors/initializers
|
||||
|
||||
nsDOMFileRequest::nsDOMFileRequest()
|
||||
: mFileData(nsnull), mReadCount(0),
|
||||
mDataLen(0), mDataFormat(0),
|
||||
mReadyState(nsIDOMFileRequest::INITIAL),
|
||||
mProgressEventWasDelayed(PR_FALSE),
|
||||
mTimerIsActive(PR_FALSE),
|
||||
mReadTotal(0), mReadTransferred(0),
|
||||
mReadComplete(PR_TRUE)
|
||||
{
|
||||
nsLayoutStatics::AddRef();
|
||||
}
|
||||
|
||||
nsDOMFileRequest::~nsDOMFileRequest()
|
||||
{
|
||||
if (mListenerManager)
|
||||
mListenerManager->Disconnect();
|
||||
|
||||
nsLayoutStatics::Release();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::Init()
|
||||
{
|
||||
// Set the original mScriptContext and mPrincipal, if available.
|
||||
// Get JSContext from stack.
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
|
||||
|
||||
if (!stack) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSContext *cx;
|
||||
|
||||
if (NS_FAILED(stack->Peek(&cx)) || !cx) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal;
|
||||
if (secMan) {
|
||||
secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
|
||||
}
|
||||
NS_ENSURE_STATE(subjectPrincipal);
|
||||
mPrincipal = subjectPrincipal;
|
||||
|
||||
nsIScriptContext* context = GetScriptContextFromJSContext(cx);
|
||||
if (context) {
|
||||
mScriptContext = context;
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
do_QueryInterface(context->GetGlobalObject());
|
||||
if (window) {
|
||||
mOwner = window->GetCurrentInnerWindow();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
|
||||
PRUint32 argc, jsval *argv)
|
||||
{
|
||||
mOwner = do_QueryInterface(aOwner);
|
||||
if (!mOwner) {
|
||||
NS_WARNING("Unexpected nsIJSNativeInitializer owner");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This object is bound to a |window|,
|
||||
// so reset the principal and script context.
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
|
||||
NS_ENSURE_STATE(scriptPrincipal);
|
||||
mPrincipal = scriptPrincipal->GetPrincipal();
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
|
||||
NS_ENSURE_STATE(sgo);
|
||||
mScriptContext = sgo->GetContext();
|
||||
NS_ENSURE_STATE(mScriptContext);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::GetInterface(const nsIID & aIID, void **aResult)
|
||||
{
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
// nsIDOMFileRequest
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::GetReadyState(PRUint16 *aReadyState)
|
||||
{
|
||||
*aReadyState = mReadyState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::GetResponse(nsAString& aResponse)
|
||||
{
|
||||
aResponse = mResponse;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::GetError(nsIDOMFileError** aError)
|
||||
{
|
||||
NS_IF_ADDREF(*aError = mError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::ReadAsBinaryString(nsIDOMFile* aFile)
|
||||
{
|
||||
return ReadFileContent(aFile, EmptyString(), FILE_AS_BINARY);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::ReadAsText(nsIDOMFile* aFile,
|
||||
const nsAString &aCharset)
|
||||
{
|
||||
return ReadFileContent(aFile, aCharset, FILE_AS_TEXT);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::ReadAsDataURL(nsIDOMFile* aFile)
|
||||
{
|
||||
return ReadFileContent(aFile, EmptyString(), FILE_AS_DATAURL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::Abort()
|
||||
{
|
||||
if (mReadyState != nsIDOMFileRequest::LOADING)
|
||||
return NS_OK;
|
||||
|
||||
//Clear progress and file data
|
||||
mProgressEventWasDelayed = PR_FALSE;
|
||||
mTimerIsActive = PR_FALSE;
|
||||
if (mProgressNotifier) {
|
||||
mProgressNotifier->Cancel();
|
||||
}
|
||||
mReadCount = 0;
|
||||
mDataLen = 0;
|
||||
|
||||
//Revert status, response and readystate attributes
|
||||
SetDOMStringToNull(mResponse);
|
||||
mReadyState = nsIDOMFileRequest::DONE;
|
||||
mError = new nsDOMFileError(nsIDOMFileError::ABORT_ERR);
|
||||
|
||||
//Non-null channel indicates a read is currently active
|
||||
if (mChannel) {
|
||||
//Cancel request requires an error status
|
||||
mChannel->Cancel(NS_ERROR_FAILURE);
|
||||
mChannel = nsnull;
|
||||
}
|
||||
mFile = nsnull;
|
||||
|
||||
//Clean up memory buffer
|
||||
PR_Free(mFileData);
|
||||
mFileData = nsnull;
|
||||
|
||||
//Dispatch the abort event
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
|
||||
|
||||
mReadyState = nsIDOMFileRequest::INITIAL;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsITimerCallback
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::Notify(nsITimer* aTimer)
|
||||
{
|
||||
mTimerIsActive = PR_FALSE;
|
||||
if (mProgressEventWasDelayed) {
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR));
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMFileRequest::StartProgressEventTimer()
|
||||
{
|
||||
if (!mProgressNotifier) {
|
||||
mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
}
|
||||
if (mProgressNotifier) {
|
||||
mProgressEventWasDelayed = PR_FALSE;
|
||||
mTimerIsActive = PR_TRUE;
|
||||
mProgressNotifier->Cancel();
|
||||
mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
// nsIStreamListener
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInputStream,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount)
|
||||
{
|
||||
//Update memory buffer to reflect the contents of the file
|
||||
mFileData = (char *)PR_Realloc(mFileData, aOffset + aCount);
|
||||
NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
aInputStream->Read(mFileData + aOffset, aCount, &mReadCount);
|
||||
mDataLen += aCount;
|
||||
mReadTransferred = mDataLen;
|
||||
|
||||
//Continuously update our binary string as data comes in
|
||||
if (mDataFormat == FILE_AS_BINARY) {
|
||||
PRUint32 oldLen = mResponse.Length();
|
||||
PRUint32 newLen = oldLen + aCount;
|
||||
PRUnichar *buf;
|
||||
|
||||
if (mResponse.GetMutableData(&buf, newLen) != newLen) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PRUnichar *bufEnd = buf + newLen;
|
||||
buf += oldLen;
|
||||
|
||||
char *source = mFileData + aOffset;
|
||||
while (buf < bufEnd) {
|
||||
*buf = *source;
|
||||
++buf;
|
||||
++source;
|
||||
}
|
||||
}
|
||||
|
||||
//Notify the timer is the appropriate timeframe has passed
|
||||
if (mTimerIsActive) {
|
||||
mProgressEventWasDelayed = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR));
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileRequest::OnStopRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
//If we're here as a result of a call from Abort(),
|
||||
//simply ignore the request.
|
||||
if (aRequest != mChannel)
|
||||
return NS_OK;
|
||||
|
||||
//Cancel the progress event timer
|
||||
mProgressEventWasDelayed = PR_FALSE;
|
||||
mTimerIsActive = PR_FALSE;
|
||||
if (mProgressNotifier) {
|
||||
mProgressNotifier->Cancel();
|
||||
}
|
||||
|
||||
//FileRequest must be in DONE stage after a load
|
||||
mReadyState = nsIDOMFileRequest::DONE;
|
||||
|
||||
//Set the status field as appropriate
|
||||
if (NS_FAILED(aStatus)) {
|
||||
DispatchError(aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
switch (mDataFormat) {
|
||||
case FILE_AS_BINARY:
|
||||
break; //Already accumulated mResponse
|
||||
case FILE_AS_TEXT:
|
||||
rv = GetAsText(mCharset, mFileData, mDataLen, mResponse);
|
||||
break;
|
||||
case FILE_AS_DATAURL:
|
||||
rv = GetAsDataURL(mFile, mFileData, mDataLen, mResponse);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//Dispatch load event to signify end of a successful load
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(LOAD_STR));
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::ReadFileContent(nsIDOMFile* aFile,
|
||||
const nsAString &aCharset,
|
||||
PRUint32 aDataFormat)
|
||||
{
|
||||
NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
|
||||
|
||||
//Implicit abort to clear any other activity going on
|
||||
Abort();
|
||||
mDataFormat = aDataFormat;
|
||||
mCharset = aCharset;
|
||||
mError = nsnull;
|
||||
|
||||
//Obtain the nsDOMFile's underlying nsIFile
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMFileInternal> domFile(do_QueryInterface(aFile));
|
||||
rv = domFile->GetInternalFile(getter_AddRefs(mFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//Establish a channel with our file
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewFileURI(getter_AddRefs(uri), mFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = NS_NewChannel(getter_AddRefs(mChannel), uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//Obtain the total size of the file before reading
|
||||
aFile->GetSize(&mReadTotal);
|
||||
|
||||
rv = mChannel->AsyncOpen(this, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//FileRequest should be in loading state here
|
||||
mReadyState = nsIDOMFileRequest::LOADING;
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMFileRequest::DispatchError(nsresult rv)
|
||||
{
|
||||
//Set the status attribute, and dispatch the error event
|
||||
switch (rv) {
|
||||
case NS_ERROR_FILE_NOT_FOUND:
|
||||
mError = new nsDOMFileError(nsIDOMFileError::NOT_FOUND_ERR);
|
||||
break;
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
mError = new nsDOMFileError(nsIDOMFileError::SECURITY_ERR);
|
||||
break;
|
||||
default:
|
||||
mError = new nsDOMFileError(nsIDOMFileError::NOT_READABLE_ERR);
|
||||
break;
|
||||
}
|
||||
|
||||
//Dispatch error event to signify load failure
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR));
|
||||
DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMFileRequest::DispatchProgressEvent(const nsAString& aType)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
|
||||
NS_LITERAL_STRING("ProgressEvent"),
|
||||
getter_AddRefs(event));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIPrivateDOMEvent> privevent(do_QueryInterface(event));
|
||||
|
||||
if (!privevent)
|
||||
return;
|
||||
|
||||
privevent->SetTrusted(PR_TRUE);
|
||||
|
||||
nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
|
||||
|
||||
if (!progress)
|
||||
return;
|
||||
|
||||
progress->InitProgressEvent(aType, PR_FALSE, PR_FALSE, mReadComplete,
|
||||
mReadTransferred, (mReadTotal == LL_MAXUINT) ? 0 : mReadTotal);
|
||||
|
||||
this->DispatchDOMEvent(nsnull, event, nsnull, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::GetAsText(const nsAString &aCharset,
|
||||
const char *aFileData,
|
||||
PRUint32 aDataLen,
|
||||
nsAString& aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCAutoString charsetGuess;
|
||||
if (!aCharset.IsEmpty()) {
|
||||
CopyUTF16toUTF8(aCharset, charsetGuess);
|
||||
} else {
|
||||
rv = GuessCharset(aFileData, aDataLen, charsetGuess);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCAutoString charset;
|
||||
nsCOMPtr<nsICharsetAlias> alias = do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = alias->GetPreferred(charsetGuess, charset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ConvertStream(aFileData, aDataLen, charset.get(), aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::GetAsDataURL(nsIFile *aFile,
|
||||
const char *aFileData,
|
||||
PRUint32 aDataLen,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aResult.AssignLiteral("data:");
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCAutoString contentType;
|
||||
rv = mimeService->GetTypeFromFile(aFile, contentType);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AppendUTF8toUTF16(contentType, aResult);
|
||||
} else {
|
||||
aResult.AppendLiteral("application/octet-stream");
|
||||
}
|
||||
aResult.AppendLiteral(";base64,");
|
||||
|
||||
PRUint32 totalRead = 0;
|
||||
do {
|
||||
PRUint32 numEncode = 4096;
|
||||
PRUint32 amtRemaining = aDataLen - totalRead;
|
||||
if (numEncode > amtRemaining)
|
||||
numEncode = amtRemaining;
|
||||
|
||||
//Unless this is the end of the file, encode in multiples of 3
|
||||
if (numEncode > 3) {
|
||||
PRUint32 leftOver = numEncode % 3;
|
||||
numEncode -= leftOver;
|
||||
}
|
||||
|
||||
//Out buffer should be at least 4/3rds the read buf, plus a terminator
|
||||
char *base64 = PL_Base64Encode(aFileData + totalRead, numEncode, nsnull);
|
||||
AppendASCIItoUTF16(nsDependentCString(base64), aResult);
|
||||
PR_Free(base64);
|
||||
|
||||
totalRead += numEncode;
|
||||
|
||||
} while (aDataLen > totalRead);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::ConvertStream(const char *aFileData,
|
||||
PRUint32 aDataLen,
|
||||
const char *aCharset,
|
||||
nsAString &aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsICharsetConverterManager> charsetConverter =
|
||||
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
|
||||
rv = charsetConverter->GetUnicodeDecoder(aCharset, getter_AddRefs(unicodeDecoder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 destLength;
|
||||
rv = unicodeDecoder->GetMaxLength(aFileData, aDataLen, &destLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aResult.SetLength(destLength); //Make sure we have enough space for the conversion
|
||||
destLength = aResult.Length();
|
||||
|
||||
PRInt32 srcLength = aDataLen;
|
||||
rv = unicodeDecoder->Convert(aFileData, &srcLength, aResult.BeginWriting(), &destLength);
|
||||
aResult.SetLength(destLength); //Trim down to the correct size
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileRequest::GuessCharset(const char *aFileData,
|
||||
PRUint32 aDataLen,
|
||||
nsACString &aCharset)
|
||||
{
|
||||
// First try the universal charset detector
|
||||
nsCOMPtr<nsICharsetDetector> detector
|
||||
= do_CreateInstance(NS_CHARSET_DETECTOR_CONTRACTID_BASE
|
||||
"universal_charset_detector");
|
||||
if (!detector) {
|
||||
// No universal charset detector, try the default charset detector
|
||||
const nsAdoptingString& detectorName =
|
||||
nsContentUtils::GetLocalizedStringPref("intl.charset.detector");
|
||||
if (!detectorName.IsEmpty()) {
|
||||
nsCAutoString detectorContractID;
|
||||
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
|
||||
AppendUTF16toUTF8(detectorName, detectorContractID);
|
||||
detector = do_CreateInstance(detectorContractID.get());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (detector) {
|
||||
mCharset.Truncate();
|
||||
detector->Init(this);
|
||||
|
||||
PRBool done;
|
||||
|
||||
rv = detector->DoIt(aFileData, aDataLen, &done);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = detector->Done();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CopyUTF16toUTF8(mCharset, aCharset);
|
||||
} else {
|
||||
// no charset detector available, check the BOM
|
||||
unsigned char sniffBuf[4];
|
||||
PRUint32 numRead = (aDataLen >= sizeof(sniffBuf) ? sizeof(sniffBuf) : aDataLen);
|
||||
memcpy(sniffBuf, aFileData, numRead);
|
||||
|
||||
if (numRead >= 4 &&
|
||||
sniffBuf[0] == 0x00 &&
|
||||
sniffBuf[1] == 0x00 &&
|
||||
sniffBuf[2] == 0xfe &&
|
||||
sniffBuf[3] == 0xff) {
|
||||
aCharset = "UTF-32BE";
|
||||
} else if (numRead >= 4 &&
|
||||
sniffBuf[0] == 0xff &&
|
||||
sniffBuf[1] == 0xfe &&
|
||||
sniffBuf[2] == 0x00 &&
|
||||
sniffBuf[3] == 0x00) {
|
||||
aCharset = "UTF-32LE";
|
||||
} else if (numRead >= 2 &&
|
||||
sniffBuf[0] == 0xfe &&
|
||||
sniffBuf[1] == 0xff) {
|
||||
aCharset = "UTF-16BE";
|
||||
} else if (numRead >= 2 &&
|
||||
sniffBuf[0] == 0xff &&
|
||||
sniffBuf[1] == 0xfe) {
|
||||
aCharset = "UTF-16LE";
|
||||
} else if (numRead >= 3 &&
|
||||
sniffBuf[0] == 0xef &&
|
||||
sniffBuf[1] == 0xbb &&
|
||||
sniffBuf[2] == 0xbf) {
|
||||
aCharset = "UTF-8";
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no charset detected, default to the system charset
|
||||
nsCOMPtr<nsIPlatformCharset> platformCharset =
|
||||
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = platformCharset->GetCharset(kPlatformCharsetSel_PlainTextInFile,
|
||||
aCharset);
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no sniffed or default charset, try UTF-8
|
||||
aCharset.AssignLiteral("UTF-8");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozila.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsDOMFileRequest_h__
|
||||
#define nsDOMFileRequest_h__
|
||||
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIJSNativeInitializer.h"
|
||||
#include "prtime.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetDetectionObserver.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMFileRequest.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIDOMFileError.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIChannel.h"
|
||||
|
||||
#include "nsXMLHttpRequest.h"
|
||||
|
||||
class nsDOMFileRequest : public nsXHREventTarget,
|
||||
public nsIDOMFileRequest,
|
||||
public nsIStreamListener,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsSupportsWeakReference,
|
||||
public nsIJSNativeInitializer,
|
||||
public nsITimerCallback,
|
||||
public nsICharsetDetectionObserver
|
||||
{
|
||||
public:
|
||||
nsDOMFileRequest();
|
||||
virtual ~nsDOMFileRequest();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_NSIDOMFILEREQUEST
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMFileRequest, nsXHREventTarget)
|
||||
|
||||
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::);
|
||||
|
||||
// nsIStreamListener
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
// nsIRequestObserver
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
||||
// nsITimerCallback
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
// nsIJSNativeInitializer
|
||||
NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
|
||||
PRUint32 argc, jsval* argv);
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
|
||||
NS_FORWARD_NSIDOMNSEVENTTARGET(nsXHREventTarget::)
|
||||
|
||||
// nsICharsetDetectionObserver
|
||||
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
|
||||
|
||||
void DispatchProgressEvent(const nsAString& aType);
|
||||
|
||||
nsresult Init();
|
||||
|
||||
protected:
|
||||
nsresult ReadFileContent(nsIDOMFile *aFile, const nsAString &aCharset, PRUint32 aDataFormat);
|
||||
nsresult GetAsText(const nsAString &aCharset,
|
||||
const char *aFileData, PRUint32 aDataLen, nsAString &aResult);
|
||||
nsresult GetAsDataURL(nsIFile *aFile, const char *aFileData, PRUint32 aDataLen, nsAString &aResult);
|
||||
nsresult GuessCharset(const char *aFileData, PRUint32 aDataLen, nsACString &aCharset);
|
||||
nsresult ConvertStream(const char *aFileData, PRUint32 aDataLen, const char *aCharset, nsAString &aResult);
|
||||
void DispatchError(nsresult rv);
|
||||
void StartProgressEventTimer();
|
||||
|
||||
char *mFileData;
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsString mCharset;
|
||||
PRUint32 mReadCount;
|
||||
PRUint32 mDataLen;
|
||||
PRUint32 mDataFormat;
|
||||
|
||||
nsString mResponse;
|
||||
PRUint16 mReadyState;
|
||||
|
||||
PRBool mProgressEventWasDelayed;
|
||||
PRBool mTimerIsActive;
|
||||
nsCOMPtr<nsIDOMFileError> mError;
|
||||
|
||||
nsCOMPtr<nsITimer> mProgressNotifier;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
||||
PRUint64 mReadTotal;
|
||||
PRUint64 mReadTransferred;
|
||||
PRPackedBool mReadComplete;
|
||||
|
||||
nsRefPtr<nsDOMEventListenerWrapper> mOnLoadEndListener;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2691,6 +2691,16 @@ nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|||
document->ClearBoxObjectFor(this);
|
||||
}
|
||||
|
||||
// Ensure that CSS transitions don't continue on an element at a
|
||||
// different place in the tree (even if reinserted before next
|
||||
// animation refresh).
|
||||
// FIXME: Need a test for this.
|
||||
if (HasFlag(NODE_HAS_PROPERTIES)) {
|
||||
DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
|
||||
DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
|
||||
DeleteProperty(nsGkAtoms::transitionsProperty);
|
||||
}
|
||||
|
||||
// Unset this since that's what the old code effectively did.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS);
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
mNode = nsnull;
|
||||
}
|
||||
|
||||
nsISupports* GetParentObject()
|
||||
nsINode* GetParentObject()
|
||||
{
|
||||
return mNode;
|
||||
}
|
||||
|
|
|
@ -1674,6 +1674,9 @@ GK_ATOM(preTransformBBoxProperty, "PreTransformBBoxProperty") // nsRect*
|
|||
GK_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
|
||||
GK_ATOM(tabWidthProperty, "TabWidthProperty") // nsTArray<TabSetting>* array of tab widths
|
||||
GK_ATOM(tableBCProperty, "TableBCProperty") // table border collapsing info (e.g. damage area, table border widths)
|
||||
GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions*
|
||||
GK_ATOM(transitionsOfBeforeProperty, "TransitionsOfBeforeProperty") // FrameTransitions*
|
||||
GK_ATOM(transitionsOfAfterProperty, "TransitionsOfAfterProperty") // FrameTransitions*
|
||||
GK_ATOM(usedMarginProperty, "UsedMarginProperty") // nsMargin*
|
||||
GK_ATOM(usedPaddingProperty, "UsedPaddingProperty") // nsMargin*
|
||||
GK_ATOM(viewProperty, "ViewProperty")
|
||||
|
|
|
@ -464,8 +464,9 @@ nsNodeUtils::CloneNodeImpl(nsINode *aNode, PRBool aDeep, nsIDOMNode **aResult)
|
|||
|
||||
class AdoptFuncData {
|
||||
public:
|
||||
AdoptFuncData(nsIDOMElement *aElement, nsNodeInfoManager *aNewNodeInfoManager,
|
||||
JSContext *aCx, JSObject *aOldScope, JSObject *aNewScope,
|
||||
AdoptFuncData(nsGenericElement *aElement,
|
||||
nsNodeInfoManager *aNewNodeInfoManager, JSContext *aCx,
|
||||
JSObject *aOldScope, JSObject *aNewScope,
|
||||
nsCOMArray<nsINode> &aNodesWithProperties)
|
||||
: mElement(aElement),
|
||||
mNewNodeInfoManager(aNewNodeInfoManager),
|
||||
|
@ -476,7 +477,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
nsIDOMElement *mElement;
|
||||
nsGenericElement *mElement;
|
||||
nsNodeInfoManager *mNewNodeInfoManager;
|
||||
JSContext *mCx;
|
||||
JSObject *mOldScope;
|
||||
|
@ -495,7 +496,7 @@ AdoptFunc(nsAttrHashKey::KeyType aKey, nsIDOMNode *aData, void* aUserArg)
|
|||
// If we were passed an element we need to clone the attribute nodes and
|
||||
// insert them into the element.
|
||||
PRBool clone = data->mElement != nsnull;
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
nsCOMPtr<nsINode> node;
|
||||
nsresult rv = nsNodeUtils::CloneAndAdopt(attr, clone, PR_TRUE,
|
||||
data->mNewNodeInfoManager,
|
||||
data->mCx, data->mOldScope,
|
||||
|
@ -520,14 +521,14 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
JSContext *aCx, JSObject *aOldScope,
|
||||
JSObject *aNewScope,
|
||||
nsCOMArray<nsINode> &aNodesWithProperties,
|
||||
nsINode *aParent, nsIDOMNode **aResult)
|
||||
nsINode *aParent, nsINode **aResult)
|
||||
{
|
||||
NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aCx,
|
||||
"If cloning or not getting a new nodeinfo we shouldn't "
|
||||
"rewrap");
|
||||
NS_PRECONDITION(!aCx || (aOldScope && aNewScope), "Must have scopes");
|
||||
NS_PRECONDITION(!aParent || !aNode->IsNodeOfType(nsINode::eDOCUMENT),
|
||||
"Can't insert document nodes into a parent");
|
||||
NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT),
|
||||
"Can't insert document or attribute nodes into a parent");
|
||||
|
||||
*aResult = nsnull;
|
||||
|
||||
|
@ -578,10 +579,8 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
if (aParent) {
|
||||
// If we're cloning we need to insert the cloned children into the cloned
|
||||
// parent.
|
||||
nsCOMPtr<nsIContent> cloneContent = do_QueryInterface(clone, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aParent->AppendChildTo(cloneContent, PR_FALSE);
|
||||
rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
|
||||
PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
|
@ -644,16 +643,13 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
// aNode's attributes.
|
||||
const nsDOMAttributeMap *map = elem->GetAttributeMap();
|
||||
if (map) {
|
||||
nsCOMPtr<nsIDOMElement> element;
|
||||
if (aClone) {
|
||||
// If we're cloning we need to insert the cloned attribute nodes into
|
||||
// the cloned element.
|
||||
element = do_QueryInterface(clone, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
AdoptFuncData data(element, nodeInfoManager, aCx, aOldScope,
|
||||
aNewScope, aNodesWithProperties);
|
||||
// If we're cloning we need to insert the cloned attribute nodes into the
|
||||
// cloned element. We assume that the clone of an nsGenericElement is also
|
||||
// an nsGenericElement.
|
||||
nsGenericElement* elemClone =
|
||||
aClone ? static_cast<nsGenericElement*>(clone.get()) : nsnull;
|
||||
AdoptFuncData data(elemClone, nodeInfoManager, aCx, aOldScope, aNewScope,
|
||||
aNodesWithProperties);
|
||||
|
||||
PRUint32 count = map->Enumerate(AdoptFunc, &data);
|
||||
NS_ENSURE_TRUE(count == map->Count(), NS_ERROR_FAILURE);
|
||||
|
@ -685,17 +681,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
// aNode's children.
|
||||
PRUint32 i, length = aNode->GetChildCount();
|
||||
for (i = 0; i < length; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsCOMPtr<nsINode> child;
|
||||
rv = CloneAndAdopt(aNode->GetChildAt(i), aClone, PR_TRUE, nodeInfoManager,
|
||||
aCx, aOldScope, aNewScope, aNodesWithProperties,
|
||||
clone, getter_AddRefs(child));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isDeepDocumentClone) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(child);
|
||||
if (content) {
|
||||
static_cast<nsDocument*>(clone.get())->
|
||||
RegisterNamedItems(content);
|
||||
}
|
||||
NS_ASSERTION(child->IsNodeOfType(nsINode::eCONTENT),
|
||||
"A clone of a child of a node is not nsIContent?");
|
||||
|
||||
nsIContent* content = static_cast<nsIContent*>(child.get());
|
||||
static_cast<nsDocument*>(clone.get())->RegisterNamedItems(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -729,7 +725,9 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
return clone ? CallQueryInterface(clone, aResult) : NS_OK;
|
||||
clone.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -167,8 +167,7 @@ public:
|
|||
nsIDOMNode **aResult)
|
||||
{
|
||||
return CloneAndAdopt(aNode, PR_TRUE, aDeep, aNewNodeInfoManager, nsnull,
|
||||
nsnull, nsnull, aNodesWithProperties, nsnull,
|
||||
aResult);
|
||||
nsnull, nsnull, aNodesWithProperties, aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,7 +198,7 @@ public:
|
|||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
return CloneAndAdopt(aNode, PR_FALSE, PR_TRUE, aNewNodeInfoManager, aCx,
|
||||
aOldScope, aNewScope, aNodesWithProperties,
|
||||
nsnull, getter_AddRefs(dummy));
|
||||
getter_AddRefs(dummy));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -312,8 +311,6 @@ private:
|
|||
* descendants) with properties. If aClone is
|
||||
* PR_TRUE every node will be followed by its
|
||||
* clone.
|
||||
* @param aParent If aClone is PR_TRUE the cloned node will be appended to
|
||||
* aParent's children. May be null.
|
||||
* @param aResult *aResult will contain the cloned node (if aClone is
|
||||
* PR_TRUE).
|
||||
*/
|
||||
|
@ -322,7 +319,30 @@ private:
|
|||
JSContext *aCx, JSObject *aOldScope,
|
||||
JSObject *aNewScope,
|
||||
nsCOMArray<nsINode> &aNodesWithProperties,
|
||||
nsINode *aParent, nsIDOMNode **aResult);
|
||||
nsIDOMNode **aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> clone;
|
||||
nsresult rv = CloneAndAdopt(aNode, aClone, aDeep, aNewNodeInfoManager,
|
||||
aCx, aOldScope, aNewScope, aNodesWithProperties,
|
||||
nsnull, getter_AddRefs(clone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return clone ? CallQueryInterface(clone, aResult) : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* See above for arguments that aren't described here.
|
||||
*
|
||||
* @param aParent If aClone is PR_TRUE the cloned node will be appended to
|
||||
* aParent's children. May be null. If not null then aNode
|
||||
* must be an nsIContent.
|
||||
*/
|
||||
static nsresult CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
||||
nsNodeInfoManager *aNewNodeInfoManager,
|
||||
JSContext *aCx, JSObject *aOldScope,
|
||||
JSObject *aNewScope,
|
||||
nsCOMArray<nsINode> &aNodesWithProperties,
|
||||
nsINode *aParent, nsINode **aResult);
|
||||
};
|
||||
|
||||
#endif // nsNodeUtils_h___
|
||||
|
|
|
@ -143,6 +143,7 @@ _TEST_FILES = test_bug5141.html \
|
|||
test_bug402150.html^headers^ \
|
||||
test_bug401662.html \
|
||||
test_bug403852.html \
|
||||
test_fileapi.html \
|
||||
test_bug403868.xml \
|
||||
test_bug405182.html \
|
||||
test_bug403841.html \
|
||||
|
@ -154,6 +155,10 @@ _TEST_FILES = test_bug5141.html \
|
|||
test_bug414796.html \
|
||||
test_bug416317-1.html \
|
||||
test_bug416317-2.html \
|
||||
test_XHRSendData.html \
|
||||
file_XHRSendData.sjs \
|
||||
file_XHRSendData_doc.xml \
|
||||
file_XHRSendData_doc.xml^headers^ \
|
||||
file_bug416317.xhtml \
|
||||
test_bug416383.html \
|
||||
test_bug417255.html \
|
||||
|
@ -238,6 +243,7 @@ _TEST_FILES = test_bug5141.html \
|
|||
test_bug454326.html \
|
||||
test_bug505783.html \
|
||||
test_bug457746.html \
|
||||
test_bug518104.html \
|
||||
bug457746.sjs \
|
||||
test_CrossSiteXHR.html \
|
||||
file_CrossSiteXHR_inner.html \
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xml:lang="en" lang="en" dir="ltr" id="html" class="unitTest" title=":root selector">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>selectorTest</title>
|
||||
<!-- (c) Disruptive Innovations 2008 -->
|
||||
<style type="text/css">
|
||||
|
@ -352,14 +352,14 @@
|
|||
|
||||
pass = false;
|
||||
try {
|
||||
root.querySelectorAll(null);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
pass = root.querySelectorAll(null).length === 0;
|
||||
} catch(e){ pass = false; }
|
||||
assert( pass, type + ".querySelectorAll null" );
|
||||
|
||||
pass = false;
|
||||
try {
|
||||
root.querySelectorAll(undefined);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
pass = root.querySelectorAll(undefined).length === 0;
|
||||
} catch(e){ pass = false; }
|
||||
assert( pass, type + ".querySelectorAll undefined" );
|
||||
|
||||
pass = false;
|
||||
|
@ -369,7 +369,7 @@
|
|||
} catch(e){ pass = true; }
|
||||
assert( pass, type + ".querySelectorAll no value" );
|
||||
|
||||
var pass = false;
|
||||
pass = false;
|
||||
try {
|
||||
root.querySelector("");
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
|
@ -377,14 +377,14 @@
|
|||
|
||||
pass = false;
|
||||
try {
|
||||
root.querySelector(null);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
pass = root.querySelector(null) === null;
|
||||
} catch(e){ pass = false; }
|
||||
assert( pass, type + ".querySelector null" );
|
||||
|
||||
pass = false;
|
||||
try {
|
||||
root.querySelector(undefined);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
pass = root.querySelector(undefined) === null;
|
||||
} catch(e){ pass = false; }
|
||||
assert( pass, type + ".querySelector undefined" );
|
||||
|
||||
pass = false;
|
||||
|
|
|
@ -36,12 +36,21 @@ is(testDoc2.inputEncoding, null, "wrong encoding");
|
|||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var testData = "blahblahblahblahblahblahblaaaaaaaah. blah.";
|
||||
testFileTxt = createFileWithDataExt(testData, ".txt");
|
||||
testFilePng = createFileWithDataExt(testData, ".png");
|
||||
testFileJpg = createFileWithDataExt(testData, ".jpg");
|
||||
testFileGif = createFileWithDataExt(testData, ".gif");
|
||||
testFileXml = createFileWithDataExt(testData, ".xml");
|
||||
testFileUnknown = createFileWithDataExt(testData, "noext");
|
||||
var extensions = [".txt",".png",".jpg",".gif",".xml", "noext"];
|
||||
var fileTypes = ["text/plain", "image/png", "image/jpeg", "image/gif", "text/xml", null];
|
||||
var testFiles = new Array;
|
||||
var testDOMFiles = new Array;
|
||||
|
||||
extensions.forEach(
|
||||
function (extension) {
|
||||
var testFile = createFileWithDataExt(testData, extension);
|
||||
testFiles.push(testFile);
|
||||
|
||||
var fileList = document.getElementById('fileList');
|
||||
fileList.value = testFile.path;
|
||||
testDOMFiles.push(fileList.files[0]);
|
||||
}
|
||||
);
|
||||
|
||||
function createFileWithDataExt(fileData, extension) {
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
|
||||
|
@ -52,10 +61,7 @@ function createFileWithDataExt(fileData, extension) {
|
|||
outStream.write(fileData, fileData.length);
|
||||
outStream.close();
|
||||
|
||||
var fileList = document.getElementById('fileList');
|
||||
fileList.value = testFile.path;
|
||||
|
||||
return fileList.files[0];
|
||||
return testFile;
|
||||
}
|
||||
|
||||
tests = [{ body: null,
|
||||
|
@ -135,42 +141,20 @@ tests = [{ body: null,
|
|||
resBody: "<!-- doc 2 -->\n<res>text</res>",
|
||||
resContentType: "foo/bar; charset=uTf-8",
|
||||
},
|
||||
{ body: testFileTxt,
|
||||
resBody: testData,
|
||||
resContentType: "text/plain",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ body: testFilePng,
|
||||
resBody: testData,
|
||||
resContentType: "image/png",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ body: testFileJpg,
|
||||
resBody: testData,
|
||||
resContentType: "image/jpeg",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ body: testFileGif,
|
||||
resBody: testData,
|
||||
resContentType: "image/gif",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ body: testFileXml,
|
||||
resBody: testData,
|
||||
resContentType: "text/xml",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ body: testFileUnknown,
|
||||
resBody: testData,
|
||||
resContentType: "",
|
||||
resContentLength: testData.length,
|
||||
},
|
||||
{ //will trigger a redirect test server-side
|
||||
body: ("TEST_REDIRECT_STR&url=" + window.location.host + window.location.pathname),
|
||||
redirect: true,
|
||||
},
|
||||
];
|
||||
|
||||
for (var i = 0; i < testDOMFiles.length; i++) {
|
||||
tests.push({ body: testDOMFiles[i],
|
||||
resBody: testData,
|
||||
resContentType: fileTypes[i],
|
||||
resContentLength: testData.length,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
for each(test in tests) {
|
||||
xhr = new XMLHttpRequest;
|
||||
|
@ -210,25 +194,15 @@ finally {
|
|||
}
|
||||
|
||||
function cleanUpData() {
|
||||
removeFileWithExt(".txt");
|
||||
removeFileWithExt(".png");
|
||||
removeFileWithExt(".jpg");
|
||||
removeFileWithExt(".gif");
|
||||
removeFileWithExt(".xml");
|
||||
removeFileWithExt("noext");
|
||||
testFiles.forEach(
|
||||
function (testFile) {
|
||||
try {
|
||||
testFile.remove(false);
|
||||
} catch (e) {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function removeFileWithExt(extension)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
|
||||
var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
|
||||
|
||||
testFile.append("testfile" + extension);
|
||||
testFile.remove(false);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -37,7 +37,7 @@ onload = function () {
|
|||
}
|
||||
|
||||
function done() {
|
||||
is(res, "ABCDEFGHIJabcdef1M2g34hi", "scripts executed in the wrong order");
|
||||
is(res, "AacBCDEFGeHIJfbd1M2g34hi", "scripts executed in the wrong order");
|
||||
ok(!fHadExecuted, "Dynamic script executed too late");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ onload = function () {
|
|||
}
|
||||
|
||||
function done() {
|
||||
is(res, "ABCDEFGHIJabcdef1M2g34hi", "scripts executed in the wrong order");
|
||||
is(res, "AacBCDEFGeHIJfbd1M2g34hi", "scripts executed in the wrong order");
|
||||
ok(!fHadExecuted, "Dynamic script executed too late");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ fileList.value = testFile.path;
|
|||
// Make sure the file is accessible with indexed notation
|
||||
var domFile = fileList.files[0];
|
||||
|
||||
is(domFile.fileName, "prefs.js", "fileName should be prefs.js");
|
||||
is(domFile.name, "prefs.js", "fileName should be prefs.js");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -23,24 +23,9 @@ function writeIt(n) {
|
|||
document.write("<span>" + n + "</span>");
|
||||
}
|
||||
|
||||
var recur = 0;
|
||||
function externalScript() {
|
||||
if (++recur == 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
base = (recur-1) * 4
|
||||
|
||||
writeIt(6 + base);
|
||||
s = document.createElement("script");
|
||||
s.src = "data:text/plain,writeIt(" + (8+base) + ");writeIt(" + (9+base) + ");externalScript();";
|
||||
document.body.appendChild(s);
|
||||
writeIt(7 + base);
|
||||
}
|
||||
|
||||
function done() {
|
||||
nodes = document.getElementsByTagName('span');
|
||||
is(nodes.length, 13, "wrong length");
|
||||
is(nodes.length, 3, "wrong length");
|
||||
for (i = 0; i < nodes.length; ++i) {
|
||||
is(nodes[i].textContent, i+1, "wrong order");
|
||||
}
|
||||
|
@ -55,10 +40,8 @@ writeIt(1);
|
|||
|
||||
</script>
|
||||
<script defer>
|
||||
writeIt(3);
|
||||
</script>
|
||||
<script>
|
||||
writeIt(2);
|
||||
</script>
|
||||
<script defer src="data:text/plain,writeIt(4);writeIt(5);"></script>
|
||||
<script defer src="data:text/plain,externalScript();"></script>
|
||||
<script>
|
||||
writeIt(3);
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=518104
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 518104</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=518104">Mozilla Bug 518104</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe id='iframe' src="data:text/html,
|
||||
<div></div><div></div>
|
||||
<script defer src='data:application/javascript,document.write(%2522<p></p>%2522);parent.done();document.close();'></script>">
|
||||
</iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 518104 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function done() {
|
||||
var iframe = document.getElementById("iframe");
|
||||
var divs = iframe.contentWindow.document.getElementsByTagName("div").length;
|
||||
is(divs, 0, "Div wasn't blown away.")
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,293 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=414796
|
||||
-->
|
||||
<title>Test for Bug 414796</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=414796">Mozilla Bug 414796</a>
|
||||
<p id="display">
|
||||
<input id="fileList" type="file"></input>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var testCounter = 0;
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
// Write a test file > 8192 characters
|
||||
|
||||
var testData = "asdfblahqwer";
|
||||
for (var i = 0; i < 10; i++) {
|
||||
testData = testData + testData;
|
||||
}
|
||||
var testData2 = testData + "a";
|
||||
var testData3 = testData + "as";
|
||||
|
||||
//Ensure we have different sizes of data for thoroughly testing data URI retrieval
|
||||
is(testData.length % 3, 0, "Need to have data length % 3 == 0");
|
||||
is(testData2.length % 3, 1, "Need to have data length % 3 == 1");
|
||||
is(testData3.length % 3, 2, "Need to have data lenght % 3 == 2");
|
||||
|
||||
//Create UTF data that should be the same for UTF-16
|
||||
var utf16Data = "\0a\0s\0d\0f\0b\0l\0a\0h\0q\0w\0e\0r";
|
||||
for (var i = 0; i < 10; i++) {
|
||||
utf16Data = utf16Data + utf16Data;
|
||||
}
|
||||
var utf16File = createFileWithData(utf16Data, "01");
|
||||
|
||||
//Create UTF data that should be the same for UTF-32
|
||||
var utf32Data = "\0\0\0a\0\0\0s\0\0\0d\0\0\0f\0\0\0b\0\0\0l\0\0\0a\0\0\0h\0\0\0q\0\0\0w\0\0\0e\0\0\0r";
|
||||
for (var i = 0; i < 10; i++) {
|
||||
utf32Data = utf32Data + utf32Data;
|
||||
}
|
||||
var utf32File = createFileWithData(utf32Data, "001");
|
||||
|
||||
//Obtain a variety of encodings so we can test async return values
|
||||
var file = createFileWithData(testData, "00");
|
||||
var domFileData = file.getAsDataURL();
|
||||
var domFileBinary = file.getAsBinary();
|
||||
|
||||
var domFileBinary2 = utf16File.getAsBinary();
|
||||
var domFileBinary3 = utf32File.getAsBinary();
|
||||
|
||||
var request1 = new FileRequest();
|
||||
request1.onload = handleTextISO1;
|
||||
request1.readAsText(file, "iso-8859-1");
|
||||
|
||||
var request2 = new FileRequest();
|
||||
request2.onload = handleTextUTF8;
|
||||
request2.readAsText(file);
|
||||
|
||||
var request3 = new FileRequest();
|
||||
request3.onload = handleTextUTF8;
|
||||
request3.readAsText(file, "");
|
||||
|
||||
var request4 = new FileRequest();
|
||||
request4.onload = handleTextUTF8;
|
||||
request4.readAsText(file, "UTF-8");
|
||||
|
||||
//Test a variety of encodings, and make sure they work properly
|
||||
//Also, test a variety of the same calls with different numbers of arguments
|
||||
var request5 = new FileRequest();
|
||||
request5.onload = handleTextUTF16;
|
||||
request5.readAsText(utf16File, "UTF-16");
|
||||
|
||||
var request6 = new FileRequest();
|
||||
request6.onload = handleTextUTF32;
|
||||
request6.readAsText(utf32File, "UTF-32");
|
||||
|
||||
//Test binary data accessor
|
||||
var request7 = new FileRequest();
|
||||
request7.onload = handleDataBinary;
|
||||
request7.readAsBinaryString(file);
|
||||
|
||||
var request71 = new FileRequest();
|
||||
request71.onload = handleDataBinary16;
|
||||
request71.readAsBinaryString(utf16File);
|
||||
|
||||
var request72 = new FileRequest();
|
||||
request72.onload = handleDataBinary32;
|
||||
request72.readAsBinaryString(utf32File);
|
||||
|
||||
//Test data URI encoding on differing file sizes
|
||||
//Testing data URI when length % 3 == 0
|
||||
var request8 = new FileRequest();
|
||||
request8.onload = handleDataURI;
|
||||
request8.readAsDataURL(file);
|
||||
|
||||
//Testing data URI when length % 3 == 1
|
||||
var file2 = createFileWithData(testData2, "02");
|
||||
var domFileData1 = file2.getAsDataURL();
|
||||
|
||||
var request9 = new FileRequest();
|
||||
request9.onload = handleDataURI1;
|
||||
request9.readAsDataURL(file2);
|
||||
|
||||
//Testing data URI when length % 3 == 2
|
||||
var file3 = createFileWithData(testData3, "03");
|
||||
var domFileData2 = file3.getAsDataURL();
|
||||
|
||||
var request10 = new FileRequest();
|
||||
request10.onload = handleDataURI2;
|
||||
request10.readAsDataURL(file3);
|
||||
|
||||
//Test asynchronous property of file access
|
||||
var globalVar = 0;
|
||||
var request105 = new FileRequest();
|
||||
request105.onload = incGlobalVar;
|
||||
request105.readAsText(file, "");
|
||||
is(globalVar, 0, "testing to make sure getAsText doesn't block subsequent execution");
|
||||
|
||||
//Create second file for testing cancelReads()
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
|
||||
var testFile4 = dirSvc.get("ProfD", Components.interfaces.nsIFile);
|
||||
testFile4.append("testfile04");
|
||||
var outStream4 = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
outStream4.init(testFile4, 0x02 | 0x08 | 0x20, 0666, 0);
|
||||
outStream4.write(testData, testData.length);
|
||||
outStream4.close();
|
||||
|
||||
var fileList = document.getElementById('fileList');
|
||||
fileList.value = testFile4.path;
|
||||
var file4 = fileList.files[0];
|
||||
|
||||
var request11 = new FileRequest();
|
||||
request11.onabort = handleCancel;
|
||||
request11.readAsText(file4);
|
||||
request11.abort();
|
||||
|
||||
//Test error handling - Note: currently throws exceptions
|
||||
/*testFile4.permissions = 0;
|
||||
var request12 = new FileRequest();
|
||||
request12.onerror = handleSecurityError;
|
||||
request12.readAsText(file4, "");
|
||||
|
||||
testFile4.remove(false);
|
||||
var request13 = new FileRequest();
|
||||
request13.onerror = handleNotFoundError;
|
||||
request13.readAsText(file4, "");*/
|
||||
|
||||
//Corresponding callback functions
|
||||
function incGlobalVar(fileAsText) {
|
||||
globalVar++;
|
||||
}
|
||||
|
||||
function handleCancel(event) {
|
||||
var fileAsText = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error.code, FileError.ABORT_ERR, "error code set to CANCELED for canceled reads");
|
||||
is(fileAsText, null, "file data should be null on canceled reads");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleTextISO1(event) {
|
||||
var fileAsText = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error, null, "error code set to null for successful data accesses");
|
||||
is(testData.length, fileAsText.length, "iso-1 async length should match testdata");
|
||||
is(testData, fileAsText, "iso-1 async string result should match testdata");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleTextUTF8(event) {
|
||||
var fileAsUTF8 = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error, null, "error code set to null for successful data accesses");
|
||||
is(testData.length, fileAsUTF8.length, "UTF-8 async length should match testdata");
|
||||
is(testData, fileAsUTF8, "UTF-8 async string result should match testdata");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleTextUTF16(event) {
|
||||
var fileAsUTF16 = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error, null, "error code set to SUCCESS for successful data accesses");
|
||||
is(testData.length, fileAsUTF16.length, "UTF-16 async length should match testdata");
|
||||
is(testData, fileAsUTF16, "UTF-16 async string result should match testdata");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleTextUTF32(event) {
|
||||
var fileAsUTF32 = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error, null, "error code set to SUCCESS for successful data accesses");
|
||||
is(testData.length, fileAsUTF32.length, "UTF-32 async length should match testdata");
|
||||
is(testData, fileAsUTF32, "UTF-32 async string result should match testdata");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
//Tests dataURI.length % 3 == 0
|
||||
function handleDataURI(event) {
|
||||
var fileAsDataURI = event.target.response;
|
||||
is(domFileData.length, fileAsDataURI.length, "data URI async length should match dom file data");
|
||||
is(domFileData, fileAsDataURI, "data URI async string result should match dom file data");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
//Tests dataURI.length % 3 == 1
|
||||
function handleDataURI1(event) {
|
||||
var fileAsDataURI = event.target.response;
|
||||
is(domFileData1.length, fileAsDataURI.length, "data URI async length should match dom file data1");
|
||||
is(domFileData1, fileAsDataURI, "data URI async string result should match dom file data1");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
//Tests dataURI.length % 3 == 2
|
||||
function handleDataURI2(event) {
|
||||
var fileAsDataURI = event.target.response;
|
||||
is(domFileData2.length, fileAsDataURI.length, "data URI async length should match dom file data2");
|
||||
is(domFileData2, fileAsDataURI, "data URI async string result should match dom file data2");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleDataBinary(event) {
|
||||
var fileAsBinary = event.target.response;
|
||||
is(domFileBinary.length, fileAsBinary.length, "binary data async length should match dom file binary");
|
||||
is(domFileBinary, fileAsBinary, "binary data async string result should match dom file binary");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleDataBinary16(event) {
|
||||
var fileAsBinary = event.target.response;
|
||||
is(domFileBinary2.length, fileAsBinary.length, "binary data async length should match dom file binary16");
|
||||
is(domFileBinary2, fileAsBinary, "binary data async string result should match dom file binary16");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleDataBinary32(event) {
|
||||
var fileAsBinary = event.target.response;
|
||||
is(domFileBinary3.length, fileAsBinary.length, "binary data async length should match dom file binary32");
|
||||
is(domFileBinary3, fileAsBinary, "binary data async string result should match dom file binary32");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleSecurityError(event) {
|
||||
var fileAsText = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error.code, FileError.SECURITY_ERR, "code for file security error should have value 18");
|
||||
is(fileAsText, null, "file content should be null when error is encountered");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function handleNotFoundError(event) {
|
||||
var fileAsText = event.target.response;
|
||||
var error = event.target.error;
|
||||
is(error.code, FileError.NOT_FOUND_ERR, "code for file not found error should have value 8");
|
||||
is(fileAsText, null, "file content should be null when error is encountered");
|
||||
testHasRun();
|
||||
}
|
||||
|
||||
function testHasRun() {
|
||||
if (++testCounter == 13) SimpleTest.finish();
|
||||
}
|
||||
|
||||
function createFileWithData(fileData, fileNum) {
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
|
||||
var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
|
||||
testFile.append("testfile" + fileNum);
|
||||
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write(fileData, fileData.length);
|
||||
outStream.close();
|
||||
|
||||
var fileList = document.getElementById('fileList');
|
||||
fileList.value = testFile.path;
|
||||
|
||||
return fileList.files[0];
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body> </html>
|
|
@ -3051,6 +3051,12 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
|
||||
do_QueryInterface(initialDataTransfer);
|
||||
|
||||
nsDragEvent *dragEvent = (nsDragEvent*)aEvent;
|
||||
|
||||
// collect any changes to moz cursor settings stored in the event's
|
||||
// data transfer.
|
||||
UpdateDragDataTransfer(dragEvent);
|
||||
|
||||
// cancelling a dragenter or dragover event means that a drop should be
|
||||
// allowed, so update the dropEffect and the canDrop state to indicate
|
||||
// that a drag is allowed. If the event isn't cancelled, a drop won't be
|
||||
|
@ -3063,7 +3069,6 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
PRUint32 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
if (nsEventStatus_eConsumeNoDefault == *aStatus) {
|
||||
// if the event has a dataTransfer set, use it.
|
||||
nsDragEvent *dragEvent = (nsDragEvent*)aEvent;
|
||||
if (dragEvent->dataTransfer) {
|
||||
// get the dataTransfer and the dropEffect that was set on it
|
||||
dataTransfer = do_QueryInterface(dragEvent->dataTransfer);
|
||||
|
@ -3852,6 +3857,12 @@ nsEventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
|
|||
if (status == nsEventStatus_eConsumeNoDefault || aMsg == NS_DRAGDROP_EXIT)
|
||||
SetContentState((aMsg == NS_DRAGDROP_ENTER) ? aTargetContent : nsnull,
|
||||
NS_EVENT_STATE_DRAGOVER);
|
||||
|
||||
// collect any changes to moz cursor settings stored in the event's
|
||||
// data transfer.
|
||||
if (aMsg == NS_DRAGDROP_LEAVE_SYNTH || aMsg == NS_DRAGDROP_EXIT_SYNTH ||
|
||||
aMsg == NS_DRAGDROP_ENTER)
|
||||
UpdateDragDataTransfer(&event);
|
||||
}
|
||||
|
||||
// Finally dispatch the event to the frame
|
||||
|
@ -3859,6 +3870,36 @@ nsEventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
|
|||
aTargetFrame->HandleEvent(aPresContext, &event, &status);
|
||||
}
|
||||
|
||||
void
|
||||
nsEventStateManager::UpdateDragDataTransfer(nsDragEvent* dragEvent)
|
||||
{
|
||||
NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!");
|
||||
if (!dragEvent->dataTransfer)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||
|
||||
if (dragSession) {
|
||||
// the initial dataTransfer is the one from the dragstart event that
|
||||
// was set on the dragSession when the drag began.
|
||||
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
|
||||
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
|
||||
|
||||
// grab the interface that has GetMozCursor.
|
||||
nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
|
||||
do_QueryInterface(initialDataTransfer);
|
||||
nsCOMPtr<nsIDOMNSDataTransfer> eventTransferNS =
|
||||
do_QueryInterface(dragEvent->dataTransfer);
|
||||
|
||||
if (initialDataTransferNS && eventTransferNS) {
|
||||
// retrieve the current moz cursor setting and save it.
|
||||
nsAutoString mozCursor;
|
||||
eventTransferNS->GetMozCursor(mozCursor);
|
||||
initialDataTransferNS->SetMozCursor(mozCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventStateManager::SetClickCount(nsPresContext* aPresContext,
|
||||
nsMouseEvent *aEvent,
|
||||
|
|
|
@ -199,6 +199,12 @@ protected:
|
|||
nsIContent* aRelatedTarget,
|
||||
nsIContent* aTargetContent,
|
||||
nsWeakFrame& aTargetFrame);
|
||||
/**
|
||||
* Update the initial drag session data transfer with any changes that occur
|
||||
* on cloned data transfer objects used for events.
|
||||
*/
|
||||
void UpdateDragDataTransfer(nsDragEvent* dragEvent);
|
||||
|
||||
nsresult SetClickCount(nsPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
|
||||
nsresult CheckForAndDispatchClick(nsPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
|
||||
void EnsureDocument(nsPresContext* aPresContext);
|
||||
|
|
|
@ -521,8 +521,9 @@ nsHTMLScriptElement::GetScriptDeferred()
|
|||
{
|
||||
PRBool defer;
|
||||
GetDefer(&defer);
|
||||
nsCOMPtr<nsIURI> uri = GetScriptURI();
|
||||
|
||||
return defer;
|
||||
return defer && uri;
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
|
|
@ -183,8 +183,7 @@ public:
|
|||
// nsIContentSink
|
||||
NS_IMETHOD WillParse(void);
|
||||
NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
|
||||
NS_IMETHOD DidBuildModel(void);
|
||||
virtual PRBool ReadyToCallDidBuildModel(PRBool aTerminated);
|
||||
NS_IMETHOD DidBuildModel(PRBool aTerminated);
|
||||
NS_IMETHOD WillInterrupt(void);
|
||||
NS_IMETHOD WillResume(void);
|
||||
NS_IMETHOD SetParser(nsIParser* aParser);
|
||||
|
@ -1755,9 +1754,9 @@ HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::DidBuildModel(void)
|
||||
HTMLContentSink::DidBuildModel(PRBool aTerminated)
|
||||
{
|
||||
DidBuildModelImpl();
|
||||
DidBuildModelImpl(aTerminated);
|
||||
|
||||
// Reflow the last batch of content
|
||||
if (mBody || mFrameset) {
|
||||
|
@ -1805,12 +1804,6 @@ HTMLContentSink::DidBuildModel(void)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
HTMLContentSink::ReadyToCallDidBuildModel(PRBool aTerminated)
|
||||
{
|
||||
return ReadyToCallDidBuildModelImpl(aTerminated);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::SetParser(nsIParser* aParser)
|
||||
{
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
// nsIContentSink
|
||||
NS_IMETHOD WillParse(void) { return NS_OK; }
|
||||
NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
|
||||
NS_IMETHOD DidBuildModel(void);
|
||||
NS_IMETHOD DidBuildModel(PRBool aTerminated);
|
||||
NS_IMETHOD WillInterrupt(void);
|
||||
NS_IMETHOD WillResume(void);
|
||||
NS_IMETHOD SetParser(nsIParser* aParser);
|
||||
|
@ -279,7 +279,7 @@ nsHTMLFragmentContentSink::WillBuildModel(nsDTDMode)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLFragmentContentSink::DidBuildModel(void)
|
||||
nsHTMLFragmentContentSink::DidBuildModel(PRBool aTerminated)
|
||||
{
|
||||
FlushText();
|
||||
|
||||
|
@ -667,7 +667,7 @@ nsHTMLFragmentContentSink::DidBuildContent()
|
|||
{
|
||||
if (!mAllContent) {
|
||||
FlushText();
|
||||
DidBuildModel(); // Release our ref to the parser now.
|
||||
DidBuildModel(PR_FALSE); // Release our ref to the parser now.
|
||||
mProcessing = PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,8 +75,9 @@ static PRLogModuleInfo* gOggDecoderLog;
|
|||
|
||||
// The number of entries in oggplay buffer list. This value is totally
|
||||
// arbitrary. Note that the actual number of video/audio frames buffered is
|
||||
// twice this, because the current implementation frees OggPlay's buffer
|
||||
// entries and stores copies of the underlying data in the FrameQueue.
|
||||
// twice this, because the current implementation releases OggPlay's buffer
|
||||
// entries and stores references or copies of the underlying data in the
|
||||
// FrameQueue.
|
||||
#define OGGPLAY_BUFFER_SIZE 5
|
||||
|
||||
// The number of frames to read before audio callback is called.
|
||||
|
|
|
@ -81,6 +81,7 @@ EXPORTS = \
|
|||
nsISMILAttr.h \
|
||||
nsSMILAnimationController.h \
|
||||
nsSMILCompositorTable.h \
|
||||
nsSMILKeySpline.h \
|
||||
nsSMILTimeContainer.h \
|
||||
nsSMILTypes.h \
|
||||
$(NULL)
|
||||
|
|
|
@ -243,14 +243,14 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID)
|
|||
// case eCSSProperty_color_interpolation_filters:
|
||||
// case eCSSProperty_display:
|
||||
// case eCSSProperty_dominant_baseline:
|
||||
// case eCSSProperty_fill_opacity:
|
||||
case eCSSProperty_fill_opacity:
|
||||
// case eCSSProperty_fill_rule:
|
||||
// case eCSSProperty_filter:
|
||||
case eCSSProperty_flood_color:
|
||||
// case eCSSProperty_flood_opacity:
|
||||
case eCSSProperty_flood_opacity:
|
||||
// case eCSSProperty_font_family:
|
||||
case eCSSProperty_font_size:
|
||||
// case eCSSProperty_font_size_adjust:
|
||||
case eCSSProperty_font_size_adjust:
|
||||
// case eCSSProperty_font_stretch:
|
||||
// case eCSSProperty_font_style:
|
||||
// case eCSSProperty_font_variant:
|
||||
|
@ -262,16 +262,16 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID)
|
|||
// case eCSSProperty_marker_mid:
|
||||
// case eCSSProperty_marker_start:
|
||||
// case eCSSProperty_mask:
|
||||
// case eCSSProperty_opacity:
|
||||
case eCSSProperty_opacity:
|
||||
// case eCSSProperty_pointer_events:
|
||||
// case eCSSProperty_shape_rendering:
|
||||
case eCSSProperty_stop_color:
|
||||
// case eCSSProperty_stop_opacity:
|
||||
case eCSSProperty_stop_opacity:
|
||||
case eCSSProperty_stroke_dashoffset:
|
||||
// case eCSSProperty_stroke_linecap:
|
||||
// case eCSSProperty_stroke_linejoin:
|
||||
// case eCSSProperty_stroke_miterlimit:
|
||||
// case eCSSProperty_stroke_opacity:
|
||||
case eCSSProperty_stroke_miterlimit:
|
||||
case eCSSProperty_stroke_opacity:
|
||||
case eCSSProperty_stroke_width:
|
||||
// case eCSSProperty_text_anchor:
|
||||
// case eCSSProperty_text_decoration:
|
||||
|
|
|
@ -65,6 +65,7 @@ struct ValueWrapper {
|
|||
// -------------------------------------
|
||||
static const nsStyleCoord sZeroCoord(0);
|
||||
static const nsStyleCoord sZeroPercent(0.0f, eStyleUnit_Percent);
|
||||
static const nsStyleCoord sZeroFactor(0.0f, eStyleUnit_Factor);
|
||||
static const nsStyleCoord sZeroColor(NS_RGB(0,0,0));
|
||||
|
||||
// Helper Methods
|
||||
|
@ -79,6 +80,8 @@ GetZeroValueForUnit(nsStyleUnit aUnit)
|
|||
return &sZeroCoord;
|
||||
case eStyleUnit_Percent:
|
||||
return &sZeroPercent;
|
||||
case eStyleUnit_Factor:
|
||||
return &sZeroFactor;
|
||||
case eStyleUnit_Color:
|
||||
return &sZeroColor;
|
||||
default:
|
||||
|
@ -97,6 +100,9 @@ InvertStyleCoordSign(nsStyleCoord& aStyleCoord)
|
|||
case eStyleUnit_Percent:
|
||||
aStyleCoord.SetPercentValue(-aStyleCoord.GetPercentValue());
|
||||
break;
|
||||
case eStyleUnit_Factor:
|
||||
aStyleCoord.SetFactorValue(-aStyleCoord.GetFactorValue());
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Calling InvertStyleCoordSign with an unsupported unit");
|
||||
break;
|
||||
|
@ -174,18 +180,6 @@ nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
|
|||
NS_ABORT_IF_FALSE(destWrapper && valueToAddWrapper,
|
||||
"these pointers shouldn't be null");
|
||||
|
||||
// At most one of our two inputs might be "unknown" (zero) values.
|
||||
// If so, replace with an actual zero value
|
||||
const nsStyleCoord* valueToAddCSSValue;
|
||||
if (valueToAddWrapper->mPropID == eCSSProperty_UNKNOWN) {
|
||||
NS_ABORT_IF_FALSE(destWrapper->mPropID != eCSSProperty_UNKNOWN,
|
||||
"At least one of our inputs should have known value");
|
||||
NS_ABORT_IF_FALSE(valueToAddWrapper->mCSSValue.GetUnit() == eStyleUnit_Null,
|
||||
"If property ID is unset, then the unit should be, too");
|
||||
valueToAddCSSValue = GetZeroValueForUnit(destWrapper->mCSSValue.GetUnit());
|
||||
} else {
|
||||
valueToAddCSSValue = &valueToAddWrapper->mCSSValue;
|
||||
}
|
||||
if (destWrapper->mPropID == eCSSProperty_UNKNOWN) {
|
||||
NS_ABORT_IF_FALSE(destWrapper->mCSSValue.IsNull(),
|
||||
"If property ID is unset, then the unit should be, too");
|
||||
|
@ -195,9 +189,16 @@ nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
|
|||
destWrapper->mPropID = valueToAddWrapper->mPropID;
|
||||
destWrapper->mPresContext = valueToAddWrapper->mPresContext;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(valueToAddWrapper->mPropID != eCSSProperty_UNKNOWN &&
|
||||
!valueToAddWrapper->mCSSValue.IsNull(),
|
||||
"Added amount should be a parsed value");
|
||||
|
||||
// Special case: font-size-adjust is explicitly non-additive
|
||||
if (destWrapper->mPropID == eCSSProperty_font_size_adjust) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return nsStyleAnimation::Add(destWrapper->mCSSValue,
|
||||
*valueToAddCSSValue, aCount) ?
|
||||
valueToAddWrapper->mCSSValue, aCount) ?
|
||||
NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -227,10 +228,9 @@ nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
|
|||
!toWrapper->mCSSValue.IsNull(),
|
||||
"ComputeDistance endpoint should be a parsed value");
|
||||
|
||||
PRBool success = nsStyleAnimation::ComputeDistance(*fromCSSValue,
|
||||
toWrapper->mCSSValue,
|
||||
aDistance);
|
||||
return success ? NS_OK : NS_ERROR_FAILURE;
|
||||
return nsStyleAnimation::ComputeDistance(*fromCSSValue, toWrapper->mCSSValue,
|
||||
aDistance) ?
|
||||
NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -47,15 +47,17 @@
|
|||
const double nsSMILKeySpline::kSampleStepSize =
|
||||
1.0 / double(kSplineTableSize - 1);
|
||||
|
||||
nsSMILKeySpline::nsSMILKeySpline(double aX1,
|
||||
double aY1,
|
||||
double aX2,
|
||||
double aY2)
|
||||
: mX1(aX1),
|
||||
mY1(aY1),
|
||||
mX2(aX2),
|
||||
mY2(aY2)
|
||||
void
|
||||
nsSMILKeySpline::Init(double aX1,
|
||||
double aY1,
|
||||
double aX2,
|
||||
double aY2)
|
||||
{
|
||||
mX1 = aX1;
|
||||
mY1 = aY1;
|
||||
mX2 = aX2;
|
||||
mY2 = aY2;
|
||||
|
||||
if (mX1 != mY1 || mX2 != mY2)
|
||||
CalcSampleValues();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
class nsSMILKeySpline
|
||||
{
|
||||
public:
|
||||
nsSMILKeySpline() { /* caller must call Init later */ }
|
||||
|
||||
/**
|
||||
* Creates a new key spline control point description.
|
||||
*
|
||||
|
@ -51,7 +53,13 @@ public:
|
|||
* SMILANIM 3.2.3. They must each be in the range 0.0 <= x <= 1.0
|
||||
*/
|
||||
nsSMILKeySpline(double aX1, double aY1,
|
||||
double aX2, double aY2);
|
||||
double aX2, double aY2)
|
||||
{
|
||||
Init(aX1, aY1, aX2, aY2);
|
||||
}
|
||||
|
||||
void Init(double aX1, double aY1,
|
||||
double aX2, double aY2);
|
||||
|
||||
/**
|
||||
* Gets the output (y) value for an input (x).
|
||||
|
@ -104,10 +112,10 @@ private:
|
|||
return 3.0 * aA1;
|
||||
}
|
||||
|
||||
const double mX1;
|
||||
const double mY1;
|
||||
const double mX2;
|
||||
const double mY2;
|
||||
double mX1;
|
||||
double mY1;
|
||||
double mX2;
|
||||
double mY2;
|
||||
|
||||
enum { kSplineTableSize = 11 };
|
||||
double mSampleValues[kSplineTableSize];
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче