Merge mozilla-central into the branch for asynchonous plugin painting (bug 596451), especially to pick up and test whether the fix for 602200 also fixes bug 607958.

This commit is contained in:
Benjamin Smedberg 2010-11-08 09:50:11 -05:00
Родитель f684c8e2a5 7696a4ae24
Коммит e8e4ffc34f
694 изменённых файлов: 36258 добавлений и 10141 удалений

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

@ -82,7 +82,6 @@ nsIStringBundle *nsAccessNode::gStringBundle = 0;
nsIStringBundle *nsAccessNode::gKeyStringBundle = 0;
nsINode *nsAccessNode::gLastFocusedNode = nsnull;
PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
nsApplicationAccessible *nsAccessNode::gApplicationAccessible = nsnull;
@ -217,7 +216,6 @@ void nsAccessNode::InitXPAccessibility()
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefBranch) {
prefBranch->GetBoolPref("accessibility.disablecache", &gIsCacheDisabled);
prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
}

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

@ -156,7 +156,7 @@ public:
*/
virtual nsINode* GetNode() const { return mContent; }
nsIContent* GetContent() const { return mContent; }
nsIDocument* GetDocumentNode() const
virtual nsIDocument* GetDocumentNode() const
{ return mContent ? mContent->GetOwnerDoc() : nsnull; }
/**
@ -212,7 +212,6 @@ protected:
static nsIStringBundle *gStringBundle;
static nsIStringBundle *gKeyStringBundle;
static PRBool gIsCacheDisabled;
static PRBool gIsFormFillEnabled;
private:

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

@ -100,6 +100,7 @@ ACCESSIBILITY_ATOM(a, "a")
ACCESSIBILITY_ATOM(abbr, "abbr")
ACCESSIBILITY_ATOM(acronym, "acronym")
ACCESSIBILITY_ATOM(area, "area")
ACCESSIBILITY_ATOM(article, "article") // HTML landmark
ACCESSIBILITY_ATOM(autocomplete, "autocomplete")
ACCESSIBILITY_ATOM(blockquote, "blockquote")
ACCESSIBILITY_ATOM(br, "br")
@ -111,7 +112,9 @@ ACCESSIBILITY_ATOM(dd, "dd")
ACCESSIBILITY_ATOM(div, "div")
ACCESSIBILITY_ATOM(dl, "dl")
ACCESSIBILITY_ATOM(dt, "dt")
ACCESSIBILITY_ATOM(footer, "footer") // HTML landmark
ACCESSIBILITY_ATOM(form, "form")
ACCESSIBILITY_ATOM(header, "header") // HTML landmark
ACCESSIBILITY_ATOM(h1, "h1")
ACCESSIBILITY_ATOM(h2, "h2")
ACCESSIBILITY_ATOM(h3, "h3")
@ -135,6 +138,7 @@ ACCESSIBILITY_ATOM(map, "map")
ACCESSIBILITY_ATOM(math, "math")
ACCESSIBILITY_ATOM(menupopup, "menupopup") // XUL
ACCESSIBILITY_ATOM(object, "object")
ACCESSIBILITY_ATOM(nav, "nav") // HTML landmark
ACCESSIBILITY_ATOM(ol, "ol")
ACCESSIBILITY_ATOM(optgroup, "optgroup")
ACCESSIBILITY_ATOM(option, "option")
@ -196,6 +200,7 @@ ACCESSIBILITY_ATOM(multiline, "multiline") // XUL
ACCESSIBILITY_ATOM(name, "name")
ACCESSIBILITY_ATOM(onclick, "onclick")
ACCESSIBILITY_ATOM(popup, "popup")
ACCESSIBILITY_ATOM(placeholder, "placeholder")
ACCESSIBILITY_ATOM(readonly, "readonly")
ACCESSIBILITY_ATOM(scope, "scope") // HTML table
ACCESSIBILITY_ATOM(seltype, "seltype") // XUL listbox
@ -289,3 +294,4 @@ ACCESSIBILITY_ATOM(live, "live")
ACCESSIBILITY_ATOM(lineNumber, "line-number")
ACCESSIBILITY_ATOM(posinset, "posinset")
ACCESSIBILITY_ATOM(setsize, "setsize")
ACCESSIBILITY_ATOM(xmlroles, "xml-roles")

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

@ -477,32 +477,33 @@ nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
nsIContent* aStartChild,
nsIContent* aEndChild)
{
#ifdef DEBUG_A11Y
#ifdef DEBUG_CONTENTMUTATION
nsAutoString tag;
aStartChild->Tag()->ToString(tag);
nsIAtom* id = aStartChild->GetID();
nsCAutoString strid;
if (id)
id->ToUTF8String(strid);
nsIAtom* atomid = aStartChild->GetID();
nsCAutoString id;
if (atomid)
atomid->ToUTF8String(id);
nsAutoString ctag;
aContainer->Tag()->ToString(ctag);
nsIAtom* cid = aContainer->GetID();
nsCAutoString strcid;
if (cid)
cid->ToUTF8String(strcid);
nsCAutoString cid;
nsIAtom* catomid = nsnull;
if (aContainer) {
aContainer->Tag()->ToString(ctag);
catomid = aContainer->GetID();
if (catomid)
catomid->ToUTF8String(cid);
}
printf("\ncontent inserted: %s@id='%s', container: %s@id='%s', end node: %p\n\n",
NS_ConvertUTF16toUTF8(tag).get(), strid.get(),
NS_ConvertUTF16toUTF8(ctag).get(), strcid.get(), aEndChild);
NS_ConvertUTF16toUTF8(tag).get(), id.get(),
NS_ConvertUTF16toUTF8(ctag).get(), cid.get(), aEndChild);
#endif
// XXX: bug 606082. aContainer is null when root element is inserted into
// document, we need to handle this and update the tree, also we need to
// update a content node of the document accessible.
if (aContainer) {
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
if (docAccessible)
docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
}
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
if (docAccessible)
docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
}
void
@ -510,21 +511,34 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
nsIContent* aContainer,
nsIContent* aChild)
{
#ifdef DEBUG_A11Y
nsAutoString id;
aChild->Tag()->ToString(id);
printf("\ncontent removed: %s\n", NS_ConvertUTF16toUTF8(id).get());
#ifdef DEBUG_CONTENTMUTATION
nsAutoString tag;
aChild->Tag()->ToString(tag);
nsIAtom* atomid = aChild->GetID();
nsCAutoString id;
if (atomid)
atomid->ToUTF8String(id);
nsAutoString ctag;
nsCAutoString cid;
nsIAtom* catomid = nsnull;
if (aContainer) {
aContainer->Tag()->ToString(ctag);
catomid = aContainer->GetID();
if (catomid)
catomid->ToUTF8String(cid);
}
printf("\ncontent removed: %s@id='%s', container: %s@id='%s'\n\n",
NS_ConvertUTF16toUTF8(tag).get(), id.get(),
NS_ConvertUTF16toUTF8(ctag).get(), cid.get());
#endif
// XXX: bug 606082. aContainer is null when root element is inserted into
// document, we need to handle this and update the tree, perhaps destroy
// the document accessible.
if (aContainer) {
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
if (docAccessible)
docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
PR_FALSE);
}
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
if (docAccessible)
docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
PR_FALSE);
}
void

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

@ -467,9 +467,6 @@ nsAccessible::GetFirstChild(nsIAccessible **aFirstChild)
NS_ENSURE_ARG_POINTER(aFirstChild);
*aFirstChild = nsnull;
if (gIsCacheDisabled)
InvalidateChildren();
PRInt32 childCount = GetChildCount();
NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);

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

@ -285,8 +285,12 @@ nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK_DEFUNCT_OBJECT;
}
if (aExtraState)
*aExtraState = 0;
if (aExtraState) {
// The root content of the document might be removed so that mContent is
// out of date.
*aExtraState = (mContent->GetCurrentDoc() == mDocument) ?
0 : nsIAccessibleStates::EXT_STATE_STALE;
}
#ifdef MOZ_XUL
nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
@ -1239,12 +1243,17 @@ void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent2,
nsEventStates aStateMask)
{
if (!aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
return;
if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
}
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent1, nsIAccessibleStates::STATE_INVALID,
PR_FALSE, PR_TRUE);
FireDelayedAccessibleEvent(event);
}
}
void nsDocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
@ -1346,22 +1355,49 @@ nsDocAccessible::UpdateTree(nsIContent* aContainerNode,
// Since this information may be not correct then we need to fire some events
// regardless the document loading state.
// Update the whole tree of this document accessible when the container is
// null (document element is inserted or removed).
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
PRBool fireAllEvents = PR_TRUE;//IsContentLoaded() || esm->IsHandlingUserInputExternal();
// We don't create new accessibles on content removal.
nsAccessible* container = aIsInsert ?
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode);
// XXX: bug 608887 reconsider accessible tree update logic because
// 1) elements appended outside the HTML body don't get accessibles;
// 2) the document having elements that should be accessible may function
// without body.
nsAccessible* container = nsnull;
if (aIsInsert) {
container = aContainerNode ?
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
this;
// The document children were changed; the root content might be affected.
if (container == this) {
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
// No root content (for example HTML document element was inserted but no
// body). Nothing to update.
if (!rootContent)
return;
// New root content has been inserted, update it and update the tree.
if (rootContent != mContent)
mContent = rootContent;
}
// XXX: Invalidate parent-child relations for container accessible and its
// children because there's no good way to find insertion point of new child
// accessibles into accessible tree. We need to invalidate children even
// there's no inserted accessibles in the end because accessible children
// are created while parent recaches child accessibles.
container->InvalidateChildren();
} else {
// Don't create new accessibles on content removal.
container = aContainerNode ?
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
this;
}
EIsFromUserInput fromUserInput = esm->IsHandlingUserInputExternal() ?

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

@ -108,6 +108,7 @@ public:
virtual nsIFrame* GetFrame();
virtual PRBool IsDefunct();
virtual nsINode* GetNode() const { return mDocument; }
virtual nsIDocument* GetDocumentNode() const { return mDocument; }
// nsAccessible
virtual PRUint32 NativeRole();

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

@ -412,16 +412,24 @@ nsHTMLTextFieldAccessible::GetNameInternal(nsAString& aName)
if (!aName.IsEmpty())
return NS_OK;
if (!mContent->GetBindingParent())
if (mContent->GetBindingParent())
{
// XXX: bug 459640
// There's a binding parent.
// This means we're part of another control, so use parent accessible for name.
// This ensures that a textbox inside of a XUL widget gets
// an accessible name.
nsAccessible* parent = GetParent();
parent->GetName(aName);
}
if (!aName.IsEmpty())
return NS_OK;
// XXX: bug 459640
// There's a binding parent.
// This means we're part of another control, so use parent accessible for name.
// This ensures that a textbox inside of a XUL widget gets
// an accessible name.
nsAccessible* parent = GetParent();
return parent ? parent->GetName(aName) : NS_OK;
// text inputs and textareas might have useful placeholder text
mContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::placeholder, aName);
return NS_OK;
}
NS_IMETHODIMP nsHTMLTextFieldAccessible::GetValue(nsAString& _retval)

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

@ -134,8 +134,10 @@ nsHyperTextAccessible::NativeRole()
if (tag == nsAccessibilityAtoms::form)
return nsIAccessibleRole::ROLE_FORM;
if (tag == nsAccessibilityAtoms::div ||
tag == nsAccessibilityAtoms::blockquote)
if (tag == nsAccessibilityAtoms::article ||
tag == nsAccessibilityAtoms::blockquote ||
tag == nsAccessibilityAtoms::div ||
tag == nsAccessibilityAtoms::nav)
return nsIAccessibleRole::ROLE_SECTION;
if (tag == nsAccessibilityAtoms::h1 ||
@ -146,6 +148,14 @@ nsHyperTextAccessible::NativeRole()
tag == nsAccessibilityAtoms::h6)
return nsIAccessibleRole::ROLE_HEADING;
// Deal with html landmark elements
if (tag == nsAccessibilityAtoms::header)
return nsIAccessibleRole::ROLE_HEADER;
if (tag == nsAccessibilityAtoms::footer)
return nsIAccessibleRole::ROLE_FOOTER;
// Treat block frames as paragraphs
nsIFrame *frame = GetFrame();
if (frame && frame->GetType() == nsAccessibilityAtoms::blockFrame &&
frame->GetContent()->Tag() != nsAccessibilityAtoms::input) {
@ -1197,6 +1207,21 @@ nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttribute
}
}
// For the html landmark elements we expose them like we do aria landmarks to
// make AT navigation schemes "just work".
if (mContent->Tag() == nsAccessibilityAtoms::nav)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("navigation"));
else if (mContent->Tag() == nsAccessibilityAtoms::header)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("banner"));
else if (mContent->Tag() == nsAccessibilityAtoms::footer)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("contentinfo"));
else if (mContent->Tag() == nsAccessibilityAtoms::article)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("main"));
return NS_OK;
}

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

@ -95,6 +95,7 @@ _TEST_FILES =\
test_descr.html \
test_editabletext_1.html \
test_editabletext_2.html \
test_elm_landmarks.html \
test_elm_listbox.xul \
$(warning test_elm_media.html temporarily disabled) \
test_elm_nsApplicationAcc.html \

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

@ -26,10 +26,6 @@
{
this.DOMNode = aDocNode;
this.eventSeq = [
new invokerChecker(EVENT_STATE_CHANGE, getAccessible(this.DOMNode))
];
this.invoke = function editabledoc_invoke() {
// Note: this should fire an EVENT_STATE_CHANGE
this.DOMNode.designMode = 'on';
@ -58,6 +54,24 @@
};
}
function invalidInput(aNodeOrID)
{
this.DOMNode = getNode(aNodeOrID);
this.invoke = function invalidInput_invoke() {
// Note: this should fire an EVENT_STATE_CHANGE
this.DOMNode.value = "I am too long";
};
this.check = function invalidInput_check() {
testStates(aNodeOrID, STATE_INVALID);
};
this.getID = function invalidInput_getID() {
return prettyName(aNodeOrID) + " became invalid";
};
}
////////////////////////////////////////////////////////////////////////////
// Do tests
@ -67,12 +81,15 @@
function doTests()
{
gQueue = new eventQueue();
gQueue = new eventQueue(nsIAccessibleEvent.EVENT_STATE_CHANGE);
// Test delayed editable state change
var doc = document.getElementById("iframe").contentDocument;
gQueue.push(new makeEditableDoc(doc));
// invalid state change
gQueue.push(new invalidInput("maxlength"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -87,6 +104,11 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=564471"
title="Make state change events async">
Mozilla Bug 564471
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=555728"
title="Fire a11y event based on HTML5 constraint validation">
Mozilla Bug 555728
</a>
<p id="display"></p>
@ -97,6 +119,9 @@
<div id="testContainer">
<iframe id="iframe"></iframe>
</div>
<input id="maxlength" maxlength="1">
<div id="eventdump"></div>
</body>
</html>

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

@ -19,11 +19,13 @@ const ROLE_DIALOG = nsIAccessibleRole.ROLE_DIALOG;
const ROLE_DOCUMENT = nsIAccessibleRole.ROLE_DOCUMENT;
const ROLE_EMBEDDED_OBJECT = nsIAccessibleRole.ROLE_EMBEDDED_OBJECT;
const ROLE_ENTRY = nsIAccessibleRole.ROLE_ENTRY;
const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
const ROLE_GRAPHIC = nsIAccessibleRole.ROLE_GRAPHIC;
const ROLE_GRID_CELL = nsIAccessibleRole.ROLE_GRID_CELL;
const ROLE_GROUPING = nsIAccessibleRole.ROLE_GROUPING;
const ROLE_HEADER = nsIAccessibleRole.ROLE_HEADER;
const ROLE_HEADING = nsIAccessibleRole.ROLE_HEADING;
const ROLE_IMAGE_MAP = nsIAccessibleRole.ROLE_IMAGE_MAP;
const ROLE_INTERNAL_FRAME = nsIAccessibleRole.ROLE_INTERNAL_FRAME;

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

@ -38,6 +38,7 @@ const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE;
const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION;
const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL;

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

@ -17,7 +17,7 @@
<script type="application/javascript">
function doTest()
{
{
var docAcc = getAccessible(document, [nsIAccessibleDocument]);
if (docAcc) {
testStates(docAcc, STATE_READONLY);
@ -28,6 +28,7 @@
testStates(docAcc, 0, EXT_STATE_EDITABLE);
testStates("article", 0, EXT_STATE_EDITABLE);
testStates("article", 0, EXT_STATE_EDITABLE);
testStates("editable_article", 0, EXT_STATE_EDITABLE);
document.designMode = "off";

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

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML landmark tests</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="common.js"></script>
<script type="application/javascript"
src="role.js"></script>
<script type="application/javascript"
src="attributes.js"></script>
<script type="application/javascript">
function doTest()
{
testRole("nav", ROLE_SECTION);
testRole("header", ROLE_HEADER);
testRole("footer", ROLE_FOOTER);
testRole("article", ROLE_SECTION);
// Some AT may look for this
testAttrs("nav", {"xml-roles" : "navigation"}, true);
testAttrs("header", {"xml-roles" : "banner"}, true);
testAttrs("footer", {"xml-roles" : "contentinfo"}, true);
testAttrs("article", {"xml-roles" : "main"}, true);
testAttrs("document", {"xml-roles" : "document"}, true); // ARIA override
// And some AT may look for this
testAttrs("nav", {"tag" : "NAV"}, true);
testAttrs("header", {"tag" : "HEADER"}, true);
testAttrs("footer", {"tag" : "FOOTER"}, true);
testAttrs("article", {"tag" : "ARTICLE"}, true);
testAttrs("document", {"tag" : "ARTICLE"}, true); // no override expected
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Provide mappings for html5 <nav> <header> <footer> <article>"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=593368">Bug 593368</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<nav id="nav">a nav</nav>
<header id="header">a header</header>
<footer id="footer">a footer</footer>
<article id="article">an article</article>
<article id="document" role="document">a document</article>
</body>
</html>

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

@ -176,6 +176,14 @@
testName("textboxinend", "This day was sunny");
testName("textbox2", "This day was");
// placeholder
testName("ph_password", "a placeholder");
testName("ph_text", "a placeholder");
testName("ph_textarea", "a placeholder");
testName("ph_text2", "a label");
testName("ph_textarea2", "a label");
testName("ph_text3", "a label");
SimpleTest.finish();
}
@ -196,6 +204,11 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=530081"
title="Clean up our tree walker ">
Mozilla Bug 530081
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=604391"
title="Use placeholder as name if name is otherwise empty">
Mozilla Bug 604391
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
@ -421,5 +434,18 @@
</label>
</form>
<!-- placeholder -->
<input id="ph_password" type="password" value="" placeholder="a placeholder" />
<input id="ph_text" type="text" placeholder="a placeholder" />
<textarea id="ph_textarea" cols="5" placeholder="a placeholder"></textarea>
<!-- placeholder does not win -->
<input id="ph_text2" type="text" aria-label="a label" placeholder="meh" />
<textarea id="ph_textarea2" cols="5" aria-labelledby="ph_text2"
placeholder="meh"></textarea>
<label for="ph_text3">a label</label>
<input id="ph_text3" placeholder="meh" />
</body>
</html>

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

@ -46,6 +46,7 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_doc.html \
test_list_editabledoc.html \
test_list.html \
test_recreation.html \

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

@ -0,0 +1,370 @@
<!DOCTYPE html>
<html>
<head>
<title>Test document root content mutations</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="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Helpers
function getDocNode(aID)
{
return getNode(aID).contentDocument;
}
function getDocChildNode(aID)
{
return getDocNode(aID).body.firstChild;
}
function rootContentReplaced(aID, aTextName)
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
new invokerChecker(EVENT_REORDER, getDocNode, aID)
];
this.finalCheck = function rootContentReplaced_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: aTextName
}
]
};
testAccessibleTree(getDocNode(aID), tree);
}
}
function rootContentRemoved(aID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, null),
new invokerChecker(EVENT_REORDER, getDocNode, aID)
];
this.preinvoke = function rootContentRemoved_preinvoke()
{
// Set up target for hide event before we invoke.
var text = getAccessible(getAccessible(getDocNode(aID)).firstChild,
[nsIAccessNode]).DOMNode;
this.eventSeq[0].target = text;
}
this.finalCheck = function rootContentRemoved_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
states: {
// Out of date root content involves stale state presence.
states: 0,
extraStates: EXT_STATE_STALE
},
children: [ ]
};
testAccessibleTree(getDocNode(aID), tree);
}
}
function rootContentInserted(aID, aTextName)
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
new invokerChecker(EVENT_REORDER, getDocNode, aID)
];
this.finalCheck = function rootContentInserted_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
states: {
states: 0,
extraStates: 0,
absentStates: 0,
absentExtraStates: EXT_STATE_STALE
},
children: [
{
role: ROLE_TEXT_LEAF,
name: aTextName
}
]
};
testAccessibleTree(getDocNode(aID), tree);
}
}
////////////////////////////////////////////////////////////////////////////
// Invokers
function writeIFrameDoc(aID)
{
this.__proto__ = new rootContentReplaced(aID, "hello");
this.invoke = function writeIFrameDoc_invoke()
{
var docNode = getDocNode(aID);
// We can't use open/write/close outside of iframe document because of
// security error.
var script = docNode.createElement("script");
script.textContent = "document.open(); document.write('hello'); document.close();";
docNode.body.appendChild(script);
}
this.getID = function writeIFrameDoc_getID()
{
return "write document";
}
}
/**
* Replace HTML element.
*/
function replaceIFrameHTMLElm(aID)
{
this.__proto__ = new rootContentReplaced(aID, "New Wave");
this.invoke = function replaceIFrameHTMLElm_invoke()
{
var docNode = getDocNode(aID);
var newHTMLNode = docNode.createElement("html");
var newBodyNode = docNode.createElement("body");
var newTextNode = docNode.createTextNode("New Wave");
newBodyNode.appendChild(newTextNode);
newHTMLNode.appendChild(newBodyNode);
docNode.replaceChild(newHTMLNode, docNode.documentElement);
}
this.getID = function replaceIFrameBody_getID()
{
return "replace HTML element";
}
}
/**
* Replace HTML body.
*/
function replaceIFrameBody(aID)
{
this.__proto__ = new rootContentReplaced(aID, "New Hello");
this.invoke = function replaceIFrameBody_invoke()
{
var docNode = getDocNode(aID);
var newBodyNode = docNode.createElement("body");
var newTextNode = docNode.createTextNode("New Hello");
newBodyNode.appendChild(newTextNode);
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
}
this.finalCheck = function replaceIFrameBody_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello"
}
]
};
testAccessibleTree(getDocNode(aID), tree);
}
this.getID = function replaceIFrameBody_getID()
{
return "replace body";
}
}
/**
* Open/close document pair.
*/
function openIFrameDoc(aID)
{
this.__proto__ = new rootContentRemoved(aID);
this.invoke = function openIFrameDoc_invoke()
{
this.preinvoke();
// Open document.
var docNode = getDocNode(aID);
var script = docNode.createElement("script");
script.textContent = "function closeMe() { document.write('Works?'); document.close(); } window.closeMe = closeMe; document.open();";
docNode.body.appendChild(script);
}
this.getID = function openIFrameDoc_getID()
{
return "open document";
}
}
function closeIFrameDoc(aID)
{
this.__proto__ = new rootContentInserted(aID, "Works?");
this.invoke = function closeIFrameDoc_invoke()
{
// Write and close document.
getDocNode(aID).write('Works?'); getDocNode(aID).close();
}
this.getID = function closeIFrameDoc_getID()
{
return "close document";
}
}
/**
* Remove/insert HTML element pair.
*/
function removeHTMLFromIFrameDoc(aID)
{
this.__proto__ = new rootContentRemoved(aID);
this.invoke = function removeHTMLFromIFrameDoc_invoke()
{
this.preinvoke();
// Remove HTML element.
var docNode = getDocNode(aID);
docNode.removeChild(docNode.firstChild);
}
this.getID = function removeHTMLFromIFrameDoc_getID()
{
return "remove HTML element";
}
}
function insertHTMLToIFrameDoc(aID)
{
this.__proto__ = new rootContentInserted(aID, "Haha");
this.invoke = function insertHTMLToIFrameDoc_invoke()
{
// Insert HTML element.
var docNode = getDocNode(aID);
var html = docNode.createElement("html");
var body = docNode.createElement("body");
var text = docNode.createTextNode("Haha");
body.appendChild(text);
html.appendChild(body);
docNode.appendChild(html);
}
this.getID = function insertHTMLToIFrameDoc_getID()
{
return "insert HTML element document";
}
}
/**
* Remove/insert HTML body pair.
*/
function removeBodyFromIFrameDoc(aID)
{
this.__proto__ = new rootContentRemoved(aID);
this.invoke = function removeBodyFromIFrameDoc_invoke()
{
this.preinvoke();
// Remove body element.
var docNode = getDocNode(aID);
docNode.documentElement.removeChild(docNode.body);
}
this.getID = function removeBodyFromIFrameDoc_getID()
{
return "remove body element";
}
}
function insertBodyToIFrameDoc(aID)
{
this.__proto__ = new rootContentInserted(aID, "Yo ho ho i butylka roma!");
this.invoke = function insertBodyToIFrameDoc_invoke()
{
// Insert body element.
var docNode = getDocNode(aID);
var body = docNode.createElement("body");
var text = docNode.createTextNode("Yo ho ho i butylka roma!");
body.appendChild(text);
docNode.documentElement.appendChild(body);
}
this.getID = function insertBodyToIFrameDoc_getID()
{
return "insert body element";
}
}
////////////////////////////////////////////////////////////////////////////
// Test
//gA11yEventDumpID = "eventdump"; // debug stuff
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new writeIFrameDoc("iframe"));
gQueue.push(new replaceIFrameHTMLElm("iframe"));
gQueue.push(new replaceIFrameBody("iframe"));
gQueue.push(new openIFrameDoc("iframe"));
gQueue.push(new closeIFrameDoc("iframe"));
gQueue.push(new removeHTMLFromIFrameDoc("iframe"));
gQueue.push(new insertHTMLToIFrameDoc("iframe"));
gQueue.push(new removeBodyFromIFrameDoc("iframe"));
gQueue.push(new insertBodyToIFrameDoc("iframe"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Update accessible tree when root element is changed"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=606082">Mozilla Bug 606082</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<iframe id="iframe"></iframe>
<div id="eventdump"></div>
</body>
</html>

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

@ -59,9 +59,9 @@ pref("extensions.logging.enabled", false);
// Preferences for AMO integration
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%");
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%?src=firefox");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/%APP%/search?q=%TERMS%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%?src=firefox");
pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/%APP%/discovery/%VERSION%/%OS%");
// Blocklist preferences
@ -239,6 +239,8 @@ pref("browser.shell.checkDefaultBrowser", true);
pref("browser.startup.page", 1);
pref("browser.startup.homepage", "chrome://branding/locale/browserconfig.properties");
pref("browser.aboutHomeSnippets.updateUrl", "http://snippets.mozilla.com/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
pref("browser.enable_automatic_image_resizing", true);
pref("browser.chrome.site_icons", true);
pref("browser.chrome.favicons", true);

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

@ -139,6 +139,10 @@ function loadSnippets()
let updateURL = localStorage["snippets-update-url"];
if (updateURL && (!lastUpdate ||
Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
// Even if fetching should fail we don't want to spam the server, thus
// set the last update time regardless its results. Will retry tomorrow.
localStorage["snippets-last-update"] = Date.now();
// Try to update from network.
let xhr = new XMLHttpRequest();
xhr.open('GET', updateURL, true);
@ -149,7 +153,6 @@ function loadSnippets()
{
if (xhr.status == 200) {
localStorage["snippets"] = xhr.responseText;
localStorage["snippets-last-update"] = Date.now();
}
showSnippets();
};
@ -162,32 +165,39 @@ function loadSnippets()
function showSnippets()
{
let snippets = localStorage["snippets"];
// If there are remotely fetched snippets, try to to show them.
if (snippets) {
let snippetsElt = document.getElementById("snippets");
snippetsElt.innerHTML = snippets;
// Scripts injected by innerHTML are inactive, so we have to relocate them
// through DOM manipulation to activate their contents.
Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) {
let relocatedScript = document.createElement("script");
relocatedScript.type = "text/javascript;version=1.8";
relocatedScript.text = elt.text;
elt.parentNode.replaceChild(relocatedScript, elt);
});
snippetsElt.hidden = false;
} else {
// If there are no saved snippets, show one of the default ones.
let defaultSnippetsElt = document.getElementById("defaultSnippets");
let entries = defaultSnippetsElt.querySelectorAll("span");
// Choose a random snippet. Assume there is always at least one.
let randIndex = Math.round(Math.random() * (entries.length - 1));
let entry = entries[randIndex];
// Inject url in the eventual link.
if (DEFAULT_SNIPPETS_URLS[randIndex]) {
let links = entry.getElementsByTagName("a");
if (links.length != 1)
return; // Something is messed up in this entry, we support just 1 link.
links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
// Injecting snippets can throw if they're invalid XML.
try {
snippetsElt.innerHTML = snippets;
// Scripts injected by innerHTML are inactive, so we have to relocate them
// through DOM manipulation to activate their contents.
Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) {
let relocatedScript = document.createElement("script");
relocatedScript.type = "text/javascript;version=1.8";
relocatedScript.text = elt.text;
elt.parentNode.replaceChild(relocatedScript, elt);
});
snippetsElt.hidden = false;
return;
} catch (ex) {
// Bad content, continue to show default snippets.
}
entry.hidden = false;
}
// Show default snippets otherwise.
let defaultSnippetsElt = document.getElementById("defaultSnippets");
let entries = defaultSnippetsElt.querySelectorAll("span");
// Choose a random snippet. Assume there is always at least one.
let randIndex = Math.round(Math.random() * (entries.length - 1));
let entry = entries[randIndex];
// Inject url in the eventual link.
if (DEFAULT_SNIPPETS_URLS[randIndex]) {
let links = entry.getElementsByTagName("a");
if (links.length != 1)
return; // Something is messed up in this entry, we support just 1 link.
links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
}
entry.hidden = false;
}

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

@ -113,15 +113,6 @@
label="&helpSafeMode.label;"
oncommand="safeModeRestart();"/>
<menuseparator/>
<menuseparator id="updateSeparator"/>
#ifdef XP_MACOSX
#ifdef MOZ_UPDATER
<menuitem id="checkForUpdates"
label="&updateCmd.label;"
class="menuitem-iconic"
oncommand="checkForUpdates();"/>
#endif
#endif
<menuseparator id="aboutSeparator"/>
<menuitem id="aboutName"
accesskey="&aboutProduct.accesskey;"

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

@ -1913,12 +1913,7 @@ function BrowserReloadSkipCache() {
BrowserReloadWithFlags(reloadFlags);
}
function BrowserHome()
{
var homePage = gHomeButton.getHomePage();
loadOneOrMoreURIs(homePage);
}
var BrowserHome = BrowserGoHome;
function BrowserGoHome(aEvent) {
if (aEvent && "button" in aEvent &&
aEvent.button == 2) // right-click: do nothing
@ -1928,6 +1923,11 @@ function BrowserGoHome(aEvent) {
var where = whereToOpenLink(aEvent, false, true);
var urls;
// Home page should open in a new tab when current tab is an app tab
if (where == "current" &&
gBrowser.selectedTab.pinned)
where = "tab";
// openUILinkIn in utilityOverlay.js doesn't handle loading multiple pages
switch (where) {
case "current":
@ -3489,9 +3489,10 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
PlacesToolbarHelper.customizeDone();
BookmarksMenuButton.customizeDone();
UpdateUrlbarSearchSplitterState();
// The url bar splitter state is dependent on whether stop/reload
// and the location bar are combined, so we need this ordering
CombinedStopReload.init();
UpdateUrlbarSearchSplitterState();
// Update the urlbar
if (gURLBar) {
@ -4987,134 +4988,159 @@ function asyncOpenWebPanel(event)
* - gatherTextUnder
*/
// Called whenever the user clicks in the content area,
// except when left-clicking on links (special case)
// should always return true for click to go through
function contentAreaClick(event, fieldNormalClicks)
{
if (!event.isTrusted || event.getPreventDefault()) {
return true;
}
/**
* Extracts linkNode and href for the current click target.
*
* @param event
* The click event.
* @return [href, linkNode].
*
* @note linkNode will be null if the click wasn't on an anchor
* element (or XLink).
*/
function hrefAndLinkNodeForClickEvent(event)
{
function isHTMLLink(aNode)
{
return aNode instanceof HTMLAnchorElement ||
aNode instanceof HTMLAreaElement ||
aNode instanceof HTMLLinkElement;
}
var target = event.target;
var linkNode;
let linkNode;
if (isHTMLLink(event.target)) {
// This is a hack to work around Gecko bug 266932.
// Walk up the DOM looking for a parent link node, to match the existing
// behaviour for left click.
// TODO: this is no more needed and should be removed in bug 325652.
let node = event.target;
while (node) {
if (isHTMLLink(node) && node.hasAttribute("href"))
linkNode = node;
node = node.parentNode;
}
}
else {
let node = event.originalTarget;
while (node && !(node instanceof HTMLAnchorElement)) {
node = node.parentNode;
}
// <a> cannot be nested. So if we find an anchor without an
// href, there is no useful <a> around the target.
if (node && node.hasAttribute("href"))
linkNode = node;
}
if (target instanceof HTMLAnchorElement ||
target instanceof HTMLAreaElement ||
target instanceof HTMLLinkElement) {
if (target.hasAttribute("href"))
linkNode = target;
if (linkNode)
return [linkNode.href, linkNode];
// xxxmpc: this is kind of a hack to work around a Gecko bug (see bug 266932)
// we're going to walk up the DOM looking for a parent link node,
// this shouldn't be necessary, but we're matching the existing behaviour for left click
var parent = target.parentNode;
while (parent) {
if (parent instanceof HTMLAnchorElement ||
parent instanceof HTMLAreaElement ||
parent instanceof HTMLLinkElement) {
if (parent.hasAttribute("href"))
linkNode = parent;
}
parent = parent.parentNode;
}
}
else {
linkNode = event.originalTarget;
while (linkNode && !(linkNode instanceof HTMLAnchorElement))
linkNode = linkNode.parentNode;
// <a> cannot be nested. So if we find an anchor without an
// href, there is no useful <a> around the target
if (linkNode && !linkNode.hasAttribute("href"))
linkNode = null;
}
var wrapper = null;
if (linkNode) {
wrapper = linkNode;
if (event.button == 0 && !event.ctrlKey && !event.shiftKey &&
!event.altKey && !event.metaKey) {
// A Web panel's links should target the main content area. Do this
// if no modifier keys are down and if there's no target or the target equals
// _main (the IE convention) or _content (the Mozilla convention).
// XXX Now that markLinkVisited is gone, we may not need to field _main and
// _content here.
target = wrapper.getAttribute("target");
if (fieldNormalClicks &&
(!target || target == "_content" || target == "_main"))
// IE uses _main, SeaMonkey uses _content, we support both
{
if (!wrapper.href)
return true;
if (wrapper.getAttribute("onclick"))
return true;
// javascript links should be executed in the current browser
if (wrapper.href.substr(0, 11) === "javascript:")
return true;
// data links should be executed in the current browser
if (wrapper.href.substr(0, 5) === "data:")
return true;
// If there is no linkNode, try simple XLink.
let href, baseURI;
let node = event.target;
while (node) {
if (node.nodeType == Node.ELEMENT_NODE) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href)
baseURI = node.baseURI;
}
node = node.parentNode;
}
try {
urlSecurityCheck(wrapper.href, wrapper.ownerDocument.nodePrincipal);
}
catch(ex) {
return false;
}
// In case of XLink, we don't return the node we got href from since
// callers expect <a>-like elements.
return [href ? makeURLAbsolute(baseURI, href) : null, null];
}
var postData = { };
var url = getShortcutOrURI(wrapper.href, postData);
if (!url)
return true;
loadURI(url, null, postData.value, false);
event.preventDefault();
return false;
}
else if (linkNode.getAttribute("rel") == "sidebar") {
// This is the Opera convention for a special link that - when clicked - allows
// you to add a sidebar panel. We support the Opera convention here. The link's
// title attribute contains the title that should be used for the sidebar panel.
PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(wrapper.href),
wrapper.getAttribute("title"),
null, null, true, true);
event.preventDefault();
return false;
}
}
else {
handleLinkClick(event, wrapper.href, linkNode);
}
/**
* Called whenever the user clicks in the content area.
*
* @param event
* The click event.
* @param isPanelClick
* Whether the event comes from a web panel.
* @note default event is prevented if the click is handled.
*/
function contentAreaClick(event, isPanelClick)
{
if (!event.isTrusted || event.getPreventDefault() || event.button == 2)
return true;
return true;
} else {
// Try simple XLink
var href, realHref, baseURI;
linkNode = target;
while (linkNode) {
if (linkNode.nodeType == Node.ELEMENT_NODE) {
wrapper = linkNode;
let [href, linkNode] = hrefAndLinkNodeForClickEvent(event);
if (!href) {
// Not a link, handle middle mouse navigation.
if (event.button == 1 &&
gPrefService.getBoolPref("middlemouse.contentLoadURL") &&
!gPrefService.getBoolPref("general.autoScroll")) {
middleMousePaste(event);
event.preventDefault();
}
return true;
}
realHref = wrapper.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (realHref) {
href = realHref;
baseURI = wrapper.baseURI
}
}
linkNode = linkNode.parentNode;
}
if (href) {
href = makeURLAbsolute(baseURI, href);
handleLinkClick(event, href, null);
return true;
}
}
if (event.button == 1 &&
gPrefService.getBoolPref("middlemouse.contentLoadURL") &&
!gPrefService.getBoolPref("general.autoScroll")) {
middleMousePaste(event);
}
return true;
}
// This code only applies if we have a linkNode (i.e. clicks on real anchor
// elements, as opposed to XLink).
if (linkNode && event.button == 0 &&
!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
// A Web panel's links should target the main content area. Do this
// if no modifier keys are down and if there's no target or the target
// equals _main (the IE convention) or _content (the Mozilla convention).
let target = linkNode.target;
let mainTarget = !target || target == "_content" || target == "_main";
if (isPanelClick && mainTarget) {
// javascript and data links should be executed in the current browser.
if (linkNode.getAttribute("onclick") ||
href.substr(0, 11) === "javascript:" ||
href.substr(0, 5) === "data:")
return true;
try {
urlSecurityCheck(href, linkNode.ownerDocument.nodePrincipal);
}
catch(ex) {
// Prevent loading unsecure destinations.
event.preventDefault();
return true;
}
let postData = {};
let url = getShortcutOrURI(href, postData);
if (!url)
return true;
loadURI(url, null, postData.value, false);
event.preventDefault();
return true;
}
if (linkNode.getAttribute("rel") == "sidebar") {
// This is the Opera convention for a special link that, when clicked,
// allows to add a sidebar panel. The link's title attribute contains
// the title that should be used for the sidebar panel.
PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(href),
linkNode.getAttribute("title"),
null, null, true, true);
event.preventDefault();
return true;
}
}
handleLinkClick(event, href, linkNode);
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
PlacesUIUtils.markPageAsFollowedLink(href);
} catch (ex) { /* Skip invalid URIs. */ }
return true;
}
/**
* Handles clicks on links.
*
* @return true if the click event was handled, false otherwise.
*/
function handleLinkClick(event, href, linkNode) {
if (event.button == 2) // right click
return false;
@ -5128,6 +5154,7 @@ function handleLinkClick(event, href, linkNode) {
if (where == "save") {
saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, true,
true, doc.documentURIObject);
event.preventDefault();
return true;
}
@ -5135,7 +5162,7 @@ function handleLinkClick(event, href, linkNode) {
openLinkIn(href, where, { fromContent: true,
referrerURI: doc.documentURIObject,
charset: doc.characterSet });
event.stopPropagation();
event.preventDefault();
return true;
}
@ -7839,17 +7866,11 @@ function switchToTabHavingURI(aURI, aOpenNew, aCallback) {
for (let i = 0; i < browsers.length; i++) {
let browser = browsers[i];
if (browser.currentURI.equals(aURI)) {
gURLBar.handleRevert();
// We need the current tab so we can check if we should close it
let prevTab = gBrowser.selectedTab;
// Focus the matching window & tab
aWindow.focus();
aWindow.gBrowser.tabContainer.selectedIndex = i;
if (aCallback)
aCallback(browser);
// Close the previously selected tab if it was empty
if (isTabEmpty(prevTab))
gBrowser.removeTab(prevTab);
return true;
}
}

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

@ -430,28 +430,24 @@
</popupset>
#ifdef CAN_DRAW_IN_TITLEBAR
<vbox id="titlebar">
<vbox id="titlebar">
<hbox id="titlebar-content">
<hbox id="appmenu-button-container" align="start">
<button id="appmenu-button"
type="menu"
#ifdef XP_WIN
label="&brandShortName;"
#else
label="&appMenuButton.label;"
#endif
style="-moz-user-focus: ignore;">
<hbox id="appmenu-button-container" align="start">
<button id="appmenu-button"
type="menu"
label="&brandShortName;"
style="-moz-user-focus: ignore;">
#include browser-appmenu.inc
</button>
</button>
</hbox>
<spacer id="titlebar-spacer" flex="1"/>
<hbox id="titlebar-buttonbox">
<toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
<toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
<toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
</hbox>
</hbox>
<spacer id="titlebar-spacer" flex="1"/>
<hbox id="titlebar-buttonbox">
<toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
<toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
<toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
</hbox>
</hbox>
</vbox>
</vbox>
#endif
<deck flex="1" id="tab-view-deck">
@ -580,13 +576,16 @@
onclick="gURLBar.handleCommand(event);"/>
</hbox>
<toolbarbutton id="urlbar-go-button"
class="chromeclass-toolbar-additional"
onclick="gURLBar.handleCommand(event);"
tooltiptext="&goEndCap.tooltip;"/>
<toolbarbutton id="urlbar-reload-button"
class="chromeclass-toolbar-additional"
command="Browser:ReloadOrDuplicate"
onclick="checkForMiddleClick(this, event);"
tooltiptext="&reloadButton.tooltip;"/>
<toolbarbutton id="urlbar-stop-button"
class="chromeclass-toolbar-additional"
command="Browser:Stop"
tooltiptext="&stopButton.tooltip;"/>
</textbox>

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

@ -524,8 +524,10 @@
browserHistory.unregisterOpenPage(this.mBrowser.registeredOpenURI);
delete this.mBrowser.registeredOpenURI;
}
browserHistory.registerOpenPage(aLocation);
this.mBrowser.registeredOpenURI = aLocation;
if (aLocation.spec != "about:blank") {
browserHistory.registerOpenPage(aLocation);
this.mBrowser.registeredOpenURI = aLocation;
}
}
if (!this.mBlank) {

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

@ -81,6 +81,8 @@ function GroupItem(listOfEls, options) {
this.locked = (options.locked ? Utils.copy(options.locked) : {});
this.topChild = null;
this.hidden = false;
this.fadeAwayUndoButtonDelay = 15000;
this.fadeAwayUndoButtonDuration = 300;
this.keepProportional = false;
@ -277,6 +279,7 @@ function GroupItem(listOfEls, options) {
// ___ Undo Close
this.$undoContainer = null;
this._undoButtonTimeoutId = null;
// ___ Superclass initialization
this._init($container[0]);
@ -637,28 +640,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
}, 50);
let remove = function() {
// close all children
let toClose = self._children.concat();
toClose.forEach(function(child) {
child.removeSubscriber(self, "close");
child.close();
});
// remove all children
self.removeAll();
GroupItems.unregister(self);
self._sendToSubscribers("close");
self.removeTrenches();
iQ(self.container).remove();
self.$undoContainer.remove();
self.$undoContainer = null;
Items.unsquish();
self.deleteData();
};
this.$undoContainer.click(function(e) {
// Only do this for clicks on this actual element.
if (e.target.nodeName != self.$undoContainer[0].nodeName)
@ -667,6 +648,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
self.$undoContainer.fadeOut(function() {
iQ(this).remove();
self.hidden = false;
self._cancelFadeAwayUndoButtonTimer();
self.$undoContainer = null;
iQ(self.container).show().animate({
@ -686,31 +668,92 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
undoClose.click(function() {
self.$undoContainer.fadeOut(remove);
self._cancelFadeAwayUndoButtonTimer();
self.$undoContainer.fadeOut(function() { self._removeHiddenGroupItem(); });
});
// After 15 seconds, fade away.
const WAIT = 15000;
const FADE = 300;
this.setupFadeAwayUndoButtonTimer();
// Cancel the fadeaway if you move the mouse over the undo
// button, and restart the countdown once you move out of it.
this.$undoContainer.mouseover(function() {
self._cancelFadeAwayUndoButtonTimer();
});
this.$undoContainer.mouseout(function() {
self.setupFadeAwayUndoButtonTimer();
});
},
let fadeaway = function() {
if (self.$undoContainer)
// ----------
// Sets up fade away undo button timeout.
setupFadeAwayUndoButtonTimer: function() {
let self = this;
if (!this._undoButtonTimeoutId) {
this._undoButtonTimeoutId = setTimeout(function() {
self._fadeAwayUndoButton();
}, this.fadeAwayUndoButtonDelay);
}
},
// ----------
// Cancels the fade away undo button timeout.
_cancelFadeAwayUndoButtonTimer: function() {
clearTimeout(this._undoButtonTimeoutId);
this._undoButtonTimeoutId = null;
},
// ----------
// Fades away the undo button
_fadeAwayUndoButton: function() {
let self = this;
if (this.$undoContainer) {
// if there is one or more orphan tabs or there is more than one group
// and other groupS are not empty, fade away the undo button.
let shouldFadeAway = GroupItems.getOrphanedTabs().length > 0;
if (!shouldFadeAway && GroupItems.groupItems.length > 1) {
shouldFadeAway =
GroupItems.groupItems.some(function(groupItem) {
return (groupItem != self && groupItem.getChildren().length > 0);
});
}
if (shouldFadeAway) {
self.$undoContainer.animate({
color: "transparent",
opacity: 0
}, {
duration: FADE,
complete: remove
duration: this.fadeAwayUndoButtonDuration,
complete: function() { self._removeHiddenGroupItem(); }
});
};
}
}
},
let timeoutId = setTimeout(fadeaway, WAIT);
// Cancel the fadeaway if you move the mouse over the undo
// button, and restart the countdown once you move out of it.
this.$undoContainer.mouseover(function() clearTimeout(timeoutId));
this.$undoContainer.mouseout(function() {
timeoutId = setTimeout(fadeaway, WAIT);
// ----------
// Removes the group item, its children and its container.
_removeHiddenGroupItem: function() {
let self = this;
// close all children
let toClose = this._children.concat();
toClose.forEach(function(child) {
child.removeSubscriber(self, "close");
child.close();
});
// remove all children
this.removeAll();
GroupItems.unregister(this);
this._sendToSubscribers("close");
this.removeTrenches();
iQ(this.container).remove();
this.$undoContainer.remove();
this.$undoContainer = null;
Items.unsquish();
this.deleteData();
},
// ----------

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

@ -1,252 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is infoitems.js.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ian Gilman <ian@iangilman.com>
* Aza Raskin <aza@mozilla.com>
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
* Ehsan Akhgari <ehsan@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 ***** */
// **********
// Title: infoitems.js
// ##########
// Class: InfoItem
// An <Item> in TabView used for displaying information, such as the welcome video.
// Note that it implements the <Subscribable> interface.
//
// ----------
// Constructor: InfoItem
//
// Parameters:
// bounds - a <Rect> for where the item should be located
// options - various options for this infoItem (see below)
//
// Possible options:
// locked - see <Item.locked>; default is {}
// dontPush - true if this infoItem shouldn't push away on creation; default is false
// immediately - place the item immediately, without animation
function InfoItem(bounds, options) {
try {
Utils.assertThrow(Utils.isRect(bounds), 'bounds');
if (typeof options == 'undefined')
options = {};
this._inited = false;
this.isAnInfoItem = true;
this.defaultSize = bounds.size();
this.locked = (options.locked ? Utils.copy(options.locked) : {});
this.bounds = new Rect(bounds);
this.isDragging = false;
var self = this;
var $container = iQ('<div>')
.addClass('info-item')
.css(this.bounds)
.appendTo('body');
this.$contents = iQ('<div>')
.appendTo($container);
var $close = iQ('<div>')
.addClass('close')
.click(function() {
self.close();
})
.appendTo($container);
// ___ locking
if (this.locked.bounds)
$container.css({cursor: 'default'});
if (this.locked.close)
$close.hide();
// ___ Superclass initialization
this._init($container[0]);
if (this.$debug)
this.$debug.css({zIndex: -1000});
// ___ Finish Up
if (!this.locked.bounds)
this.draggable();
// ___ Position
if (!options.dontPush)
this.snap(options.immediately);
this._inited = true;
this.save();
} catch(e) {
Utils.log(e);
}
};
// ----------
InfoItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// ----------
// Function: getStorageData
// Returns all of the info worth storing about this item.
getStorageData: function InfoItem_getStorageData() {
var data = null;
try {
data = {
bounds: this.getBounds(),
locked: Utils.copy(this.locked)
};
} catch(e) {
Utils.log(e);
}
return data;
},
// ----------
// Function: save
// Saves this item to persistent storage.
save: function InfoItem_save() {
try {
if (!this._inited) // too soon to save now
return;
var data = this.getStorageData();
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: setBounds
// Sets the bounds with the given <Rect>, animating unless "immediately" is false.
setBounds: function InfoItem_setBounds(rect, immediately) {
try {
Utils.assertThrow(Utils.isRect(rect), 'InfoItem.setBounds: rect must be a real rectangle!');
// ___ Determine what has changed
var css = {};
if (rect.left != this.bounds.left)
css.left = rect.left;
if (rect.top != this.bounds.top)
css.top = rect.top;
if (rect.width != this.bounds.width)
css.width = rect.width;
if (rect.height != this.bounds.height)
css.height = rect.height;
if (Utils.isEmptyObject(css))
return;
this.bounds = new Rect(rect);
Utils.assertThrow(Utils.isRect(this.bounds),
'InfoItem.setBounds: this.bounds must be a real rectangle!');
// ___ Update our representation
if (immediately) {
iQ(this.container).css(css);
} else {
TabItems.pausePainting();
iQ(this.container).animate(css, {
duration: 350,
easing: "tabviewBounce",
complete: function() {
TabItems.resumePainting();
}
});
}
this._updateDebugBounds();
this.setTrenches(rect);
this.save();
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: setZ
// Set the Z order for the item's container.
setZ: function InfoItem_setZ(value) {
try {
Utils.assertThrow(typeof value == 'number', 'value must be a number');
this.zIndex = value;
iQ(this.container).css({zIndex: value});
if (this.$debug)
this.$debug.css({zIndex: value + 1});
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: close
// Closes the item.
close: function InfoItem_close() {
try {
this._sendToSubscribers("close");
this.removeTrenches();
iQ(this.container).fadeOut(function() {
iQ(this).remove();
Items.unsquish();
});
} catch(e) {
Utils.log(e);
}
},
// ----------
// Function: html
// Sets the item's container's html to the specified value.
html: function InfoItem_html(value) {
try {
Utils.assertThrow(typeof value == 'string', 'value must be a string');
this.$contents.html(value);
} catch(e) {
Utils.log(e);
}
}
});

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

@ -52,8 +52,5 @@ XPCOMUtils.defineLazyGetter(this, "gPrivateBrowsing", function() {
#include tabitems.js
#include drag.js
#include trench.js
#include infoitems.js
#include ui.js
#include search.js

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

@ -249,16 +249,19 @@ let UI = {
// Resets the Panorama view to have just one group with all tabs
// and, if firstTime == true, add the welcome video/tab
reset: function UI_reset(firstTime) {
let padding = 10;
let infoWidth = 350;
let infoHeight = 232;
let padding = Trenches.defaultRadius;
let welcomeWidth = 300;
let pageBounds = Items.getPageBounds();
pageBounds.inset(padding, padding);
let $actions = iQ("#actions");
if ($actions)
pageBounds.width -= $actions.width();
// ___ make a fresh groupItem
let box = new Rect(pageBounds);
box.width =
Math.min(box.width * 0.667, pageBounds.width - (infoWidth + padding));
box.width = Math.min(box.width * 0.667,
pageBounds.width - (welcomeWidth + padding));
box.height = box.height * 0.667;
GroupItems.groupItems.forEach(function(group) {
@ -280,17 +283,18 @@ let UI = {
if (firstTime) {
gPrefBranch.setBoolPref("experienced_first_run", true);
// ___ make info item
let video =
"http://videos-cdn.mozilla.net/firefox4beta/tabcandy_howto.webm";
let html =
"<div class='intro'>"
+ "<video src='" + video + "' width='100%' preload controls>"
+ "</div>";
let infoBox = new Rect(box.right + padding, box.top,
infoWidth, infoHeight);
let infoItem = new InfoItem(infoBox);
infoItem.html(html);
let url = gPrefBranch.getCharPref("welcome_url");
let newTab = gBrowser.loadOneTab(url, {inBackground: true});
let newTabItem = newTab.tabItem;
let parent = newTabItem.parent;
Utils.assert(parent, "should have a parent");
newTabItem.parent.remove(newTabItem);
let aspect = TabItems.tabHeight / TabItems.tabWidth;
let welcomeBounds = new Rect(box.right + padding, box.top,
welcomeWidth, welcomeWidth * aspect);
newTabItem.setBounds(welcomeBounds, true);
GroupItems.setActiveGroupItem(groupItem);
}
},

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

@ -221,6 +221,7 @@ _BROWSER_FILES = \
browser_aboutHome.js \
app_bug575561.html \
app_subframe_bug575561.html \
browser_contentAreaClick.js \
$(NULL)
# compartment-disabled

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

@ -94,6 +94,32 @@ let gTests = [
}
},
{
desc: "Check default snippets are shown if snippets are invalid xml",
setup: function ()
{
let storage = getStorage();
// This must be some incorrect xhtml code.
storage.setItem("snippets", "<p><b></p></b>");
},
run: function ()
{
let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
let snippetsElt = doc.getElementById("snippets");
ok(snippetsElt, "Found snippets element");
ok(snippetsElt.hidden, "Snippets element is hidden");
let defaultsElt = doc.getElementById("defaultSnippets");
ok(defaultsElt, "Found default snippets element")
ok(Array.some(defaultsElt.getElementsByTagName("span"), function(elt) {
return !elt.hidden;
}), "A default snippet is visible.");
executeSoon(runNextTest);
}
},
];
function test()

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

@ -0,0 +1,296 @@
/* ***** 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 Firefox Browser Test Code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net>
*
* 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 ***** */
/**
* Test for bug 549340.
* Test for browser.js::contentAreaClick() util.
*
* The test opens a new browser window, then replaces browser.js methods invoked
* by contentAreaClick with a mock function that tracks which methods have been
* called.
* Each sub-test synthesizes a mouse click event on links injected in content,
* the event is collected by a click handler that ensures that contentAreaClick
* correctly prevent default events, and follows the correct code path.
*/
let gTests = [
{
desc: "Simple left click",
setup: function() {},
clean: function() {},
event: {},
target: "commonlink",
expectedInvokedMethods: [],
preventDefault: false,
},
{
desc: "Ctrl/Cmd left click",
setup: function() {},
clean: function() {},
event: { ctrlKey: true,
metaKey: true },
target: "commonlink",
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
// The next test was once handling feedService.forcePreview(). Now it should
// just be like Alt click.
{
desc: "Shift+Alt left click",
setup: function() {},
clean: function() {},
event: { shiftKey: true,
altKey: true },
target: "commonlink",
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
preventDefault: true,
},
{
desc: "Shift click",
setup: function() {},
clean: function() {},
event: { shiftKey: true },
target: "commonlink",
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
{
desc: "Alt click",
setup: function() {},
clean: function() {},
event: { altKey: true },
target: "commonlink",
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
preventDefault: true,
},
{
desc: "Panel click",
setup: function() {},
clean: function() {},
event: {},
target: "panellink",
expectedInvokedMethods: [ "urlSecurityCheck", "getShortcutOrURI", "loadURI" ],
preventDefault: true,
},
{
desc: "Simple middle click opentab",
setup: function() {},
clean: function() {},
event: { button: 1 },
target: "commonlink",
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
{
desc: "Simple middle click openwin",
setup: function() {
gPrefService.setBoolPref("browser.tabs.opentabfor.middleclick", false);
},
clean: function() {
try {
gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick");
} catch(ex) {}
},
event: { button: 1 },
target: "commonlink",
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
{
desc: "Middle mouse paste",
setup: function() {
gPrefService.setBoolPref("middlemouse.contentLoadURL", true);
gPrefService.setBoolPref("general.autoScroll", false);
},
clean: function() {
try {
gPrefService.clearUserPref("middlemouse.contentLoadURL");
} catch(ex) {}
try {
gPrefService.clearUserPref("general.autoScroll");
} catch(ex) {}
},
event: { button: 1 },
target: "emptylink",
expectedInvokedMethods: [ "middleMousePaste" ],
preventDefault: true,
},
];
// Array of method names that will be replaced in the new window.
let gReplacedMethods = [
"middleMousePaste",
"urlSecurityCheck",
"loadURI",
"gatherTextUnder",
"saveURL",
"openLinkIn",
"getShortcutOrURI",
];
// Reference to the new window.
let gTestWin = null;
// List of methods invoked by a specific call to contentAreaClick.
let gInvokedMethods = [];
// The test currently running.
let gCurrentTest = null;
function test() {
waitForExplicitFinish();
gTestWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
gTestWin.addEventListener("load", function (event) {
info("Window loaded.");
gTestWin.removeEventListener("load", arguments.callee, false);
waitForFocus(function() {
info("Setting up browser...");
setupTestBrowserWindow();
info("Running tests...");
executeSoon(runNextTest);
}, gTestWin.content, true);
}, false);
}
// Click handler used to steal click events.
let gClickHandler = {
handleEvent: function (event) {
let linkId = event.target.id;
is(event.type, "click",
gCurrentTest.desc + ":Handler received a click event on " + linkId);
let isPanelClick = linkId == "panellink";
let returnValue = gTestWin.contentAreaClick(event, isPanelClick);
let prevent = event.getPreventDefault();
is(prevent, gCurrentTest.preventDefault,
gCurrentTest.desc + ": event.getPreventDefault() is correct (" + prevent + ")")
// Check that all required methods have been called.
gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) {
isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1,
gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
});
if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
is(false, "More than the expected methods have been called");
gInvokedMethods.forEach(function (method) info(method + " was invoked"));
}
event.preventDefault();
event.stopPropagation();
executeSoon(runNextTest);
}
}
// Wraps around the methods' replacement mock function.
function wrapperMethod(aInvokedMethods, aMethodName) {
return function () {
aInvokedMethods.push(aMethodName);
// At least getShortcutOrURI requires to return url that is the first param.
return arguments[0];
}
}
function setupTestBrowserWindow() {
// Steal click events and don't propagate them.
gTestWin.addEventListener("click", gClickHandler, true);
// Replace methods.
gReplacedMethods.forEach(function (aMethodName) {
gTestWin["old_" + aMethodName] = gTestWin[aMethodName];
gTestWin[aMethodName] = wrapperMethod(gInvokedMethods, aMethodName);
});
// Inject links in content.
let doc = gTestWin.content.document;
let mainDiv = doc.createElement("div");
mainDiv.innerHTML =
'<a id="commonlink" href="http://mochi.test/moz/">Common link</a>' +
'<a id="panellink" href="http://mochi.test/moz/">Panel link</a>' +
'<a id="emptylink">Empty link</a>';
doc.body.appendChild(mainDiv);
}
function runNextTest() {
if (gCurrentTest) {
info(gCurrentTest.desc + ": cleaning up...")
gCurrentTest.clean();
gInvokedMethods.length = 0;
}
if (gTests.length > 0) {
gCurrentTest = gTests.shift();
info(gCurrentTest.desc + ": starting...");
// Prepare for test.
gCurrentTest.setup();
// Fire click event.
let target = gTestWin.content.document.getElementById(gCurrentTest.target);
ok(target, gCurrentTest.desc + ": target is valid (" + target.id + ")");
EventUtils.synthesizeMouse(target, 2, 2, gCurrentTest.event, gTestWin.content);
}
else {
// No more tests to run.
finishTest()
}
}
function finishTest() {
info("Restoring browser...");
gTestWin.removeEventListener("click", gClickHandler, true);
// Restore original methods.
gReplacedMethods.forEach(function (aMethodName) {
gTestWin[aMethodName] = gTestWin["old_" + aMethodName];
delete gTestWin["old_" + aMethodName];
});
gTestWin.close();
finish();
}

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

@ -121,7 +121,7 @@ var gTestSteps = [
},
function() {
info("Running step 7 - remove tab immediately");
let tab = gBrowser.addTab("about:blank");
let tab = gBrowser.addTab("about:logo");
gBrowser.removeTab(tab);
ensure_opentabs_match_db();
nextStep();
@ -209,6 +209,8 @@ function ensure_opentabs_match_db() {
for (let i = 0; i < browserWin.gBrowser.tabContainer.childElementCount; i++) {
let browser = browserWin.gBrowser.getBrowserAtIndex(i);
let url = browser.currentURI.spec;
if (url == "about:blank")
continue;
if (!(url in tabs))
tabs[url] = 1;
else
@ -249,6 +251,10 @@ function ensure_opentabs_match_db() {
ok(dbtabs.indexOf(url) > -1,
"tab is open (" + tabs[url] + " times) and should recorded in db: " + url);
}
dbtabs.forEach(function (url) {
ok(url in tabs,
"db-recorded tab should actually exist: " + url);
});
}
/**

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

@ -53,6 +53,7 @@ _BROWSER_FILES = \
browser_tabview_bug594176.js \
browser_tabview_bug595191.js \
browser_tabview_bug595518.js \
browser_tabview_bug595521.js \
browser_tabview_bug595804.js \
browser_tabview_bug595930.js \
browser_tabview_bug595943.js \

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

@ -0,0 +1,101 @@
/* ***** 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 a test for bug 595521.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Raymond Lee <raymond@appcoast.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 ***** */
let fadeAwayUndoButtonDelay;
let fadeAwayUndoButtonDuration;
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", testCloseLastGroup, false);
TabView.toggle();
}
function testCloseLastGroup() {
window.removeEventListener("tabviewshown", testCloseLastGroup, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1, "Has one group only");
let groupItem = contentWindow.GroupItems.groupItems[0];
let checkExistence = function() {
is(contentWindow.GroupItems.groupItems.length, 1,
"Still has one group after delay");
EventUtils.sendMouseEvent(
{ type: "click" }, groupItem.$undoContainer[0], contentWindow);
};
groupItem.addSubscriber(groupItem, "groupHidden", function() {
groupItem.removeSubscriber(groupItem, "groupHidden");
// it should still stay after 3 ms.
setTimeout(checkExistence, 3);
});
groupItem.addSubscriber(groupItem, "groupShown", function() {
groupItem.removeSubscriber(groupItem, "groupShown");
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
groupItem.fadeAwayUndoButtonDelay = fadeAwayUndoButtonDelay;
groupItem.fadeAwayUndoButtonDuration = fadeAwayUndoButtonDuration;
finish();
};
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
});
let closeButton = groupItem.container.getElementsByClassName("close");
ok(closeButton, "Group item close button exists");
// store the original values
fadeAwayUndoButtonDelay = groupItem.fadeAwayUndoButtonDelay;
fadeAwayUndoButtonDuration = groupItem.fadeAwayUndoButtonDuration;
// set both fade away delay and duration to 1ms
groupItem.fadeAwayUndoButtonDelay = 1;
groupItem.fadeAwayUndoButtonDuration = 1;
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
}

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

@ -35,15 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
let newWin;
let prefService;
function test() {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
prefService =
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).
getBranch("browser.panorama.");
// make sure we don't trigger the 'first run' behavior
prefService.setBoolPref("experienced_first_run", true);
waitForExplicitFinish();
@ -104,7 +97,6 @@ function test() {
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphan tabs");
// clean up and finish
prefService.setBoolPref("experienced_first_run", false);
newWin.close();
finish();

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

@ -44,8 +44,10 @@ function test() {
ok(!TabView.isVisible(), "Main window TabView is hidden");
ok(experienced(), "should start as experienced");
prefsBranch.setBoolPref("experienced_first_run", false);
ok(!experienced(), "not experienced");
ok(!experienced(), "set to not experienced");
newWindowWithTabView(checkFirstRun, part2);
}
@ -58,11 +60,14 @@ function experienced() {
function checkFirstRun(win) {
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let infoItems = contentWindow.iQ(".info-item");
is(infoItems.length, 1, "There should be an info item");
is(win.gBrowser.tabs.length, 2, "There should be two tabs");
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There should be one group");
is(groupItems[0].getChildren().length, 1, "...with one child");
let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
is(orphanTabCount, 1, "There should also be an orphaned tab");
ok(experienced(), "we're now experienced");
}
@ -74,12 +79,19 @@ function part2() {
function checkNotFirstRun(win) {
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let infoItems = contentWindow.iQ(".info-item");
is(infoItems.length, 0, "There should be no info items");
is(win.gBrowser.tabs.length, 1, "There should be one tab");
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There should be one group");
is(groupItems[0].getChildren().length, 1, "...with one child");
let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
is(orphanTabCount, 0, "There should also be no orphaned tabs");
}
function endGame() {
ok(!TabView.isVisible(), "Main window TabView is still hidden");
ok(experienced(), "should finish as experienced");
finish();
}

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

@ -161,7 +161,7 @@
pasteAndGo.setAttribute("label", label);
pasteAndGo.setAttribute("anonid", "paste-and-go");
pasteAndGo.setAttribute("oncommand",
"gURLBar.value = ''; goDoCommand('cmd_paste'); gURLBar.handleCommand();");
"gURLBar.select(); goDoCommand('cmd_paste'); gURLBar.handleCommand();");
cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling);
}
]]></constructor>
@ -248,8 +248,13 @@
if (action) {
url = action.param;
if (!(aTriggeringEvent && aTriggeringEvent.altKey)) {
if (action.type == "switchtab")
switchToTabHavingURI(url);
if (action.type == "switchtab") {
this.handleRevert();
let prevTab = gBrowser.selectedTab;
if (switchToTabHavingURI(url) &&
isTabEmpty(prevTab))
gBrowser.removeTab(prevTab);
}
return;
}
}

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

@ -412,9 +412,8 @@ function isBidiEnabled() {
function openAboutDialog() {
var enumerator = Services.wm.getEnumerator("Browser:About");
while (enumerator.hasMoreElements()) {
// Only open one about window (Bug 599573)
let win = enumerator.getNext();
if (win.opener != window)
continue;
win.focus();
return;
}
@ -486,107 +485,12 @@ function openFeedbackPage()
openUILinkIn("http://input.mozilla.com/feedback", "tab");
}
#ifdef MOZ_UPDATER
/**
* Opens the update manager and checks for updates to the application.
*/
function checkForUpdates()
{
var um =
Components.classes["@mozilla.org/updates/update-manager;1"].
getService(Components.interfaces.nsIUpdateManager);
var prompter =
Components.classes["@mozilla.org/updates/update-prompt;1"].
createInstance(Components.interfaces.nsIUpdatePrompt);
// If there's an update ready to be applied, show the "Update Downloaded"
// UI instead and let the user know they have to restart the browser for
// the changes to be applied.
if (um.activeUpdate && um.activeUpdate.state == "pending")
prompter.showUpdateDownloaded(um.activeUpdate);
else
prompter.checkForUpdates();
}
#endif
#ifdef MOZ_UPDATER
/**
* Updates an element to reflect the state of available update services.
*/
function setupCheckForUpdates(checkForUpdates, aStringBundle)
{
var updates =
Components.classes["@mozilla.org/updates/update-service;1"].
getService(Components.interfaces.nsIApplicationUpdateService);
var um =
Components.classes["@mozilla.org/updates/update-manager;1"].
getService(Components.interfaces.nsIUpdateManager);
// Disable the UI if the update enabled pref has been locked by the
// administrator or if we cannot update for some other reason
var canCheckForUpdates = updates.canCheckForUpdates;
checkForUpdates.setAttribute("disabled", !canCheckForUpdates);
if (!canCheckForUpdates)
return;
var activeUpdate = um.activeUpdate;
// If there's an active update, substitute its name into the label
// we show for this item, otherwise display a generic label.
function getStringWithUpdateName(key) {
if (activeUpdate && activeUpdate.name)
return aStringBundle.formatStringFromName(key, [activeUpdate.name], 1);
return aStringBundle.GetStringFromName(key + "Fallback");
}
// By default, show "Check for Updates..."
var key = "default";
if (activeUpdate) {
switch (activeUpdate.state) {
case "downloading":
// If we're downloading an update at present, show the text:
// "Downloading Firefox x.x..." otherwise we're paused, and show
// "Resume Downloading Firefox x.x..."
key = updates.isDownloading ? "downloading" : "resume";
break;
case "pending":
// If we're waiting for the user to restart, show: "Apply Downloaded
// Updates Now..."
key = "pending";
break;
}
}
checkForUpdates.label = getStringWithUpdateName("updatesItem_" + key);
checkForUpdates.accessKey = aStringBundle.
GetStringFromName("updatesItem_" + key + ".accesskey");
if (um.activeUpdate && updates.isDownloading)
checkForUpdates.setAttribute("loading", "true");
else
checkForUpdates.removeAttribute("loading");
}
#endif
function buildHelpMenu()
{
// Enable/disable the "Report Web Forgery" menu item. safebrowsing object
// may not exist in OSX
if (typeof safebrowsing != "undefined")
safebrowsing.setReportPhishingMenu();
#ifdef XP_MACOSX
#ifdef MOZ_UPDATER
var checkForUpdates = document.getElementById("checkForUpdates");
var browserBundle = document.getElementById("bundle_browser").stringBundle;
setupCheckForUpdates(checkForUpdates, browserBundle);
#else
// Needed by safebrowsing for inserting its menuitem so just hide it
document.getElementById("updateSeparator").hidden = true;
#endif
#else
// Needed by safebrowsing for inserting its menuitem so just hide it
document.getElementById("updateSeparator").hidden = true;
#endif
}
function isElementVisible(aElement)

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

@ -1,5 +1,6 @@
pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
pref("browser.panorama.welcome_url", "http://www.mozilla.com/firefox/panorama/");
// The time interval between checks for a new version (in seconds)
// nightly=8 hours, official=24 hours
pref("app.update.interval", 28800);

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

@ -1,5 +1,6 @@
pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
pref("browser.panorama.welcome_url", "http://www.mozilla.com/firefox/panorama/");
// The time interval between checks for a new version (in seconds)
// nightly=8 hours, official=24 hours
pref("app.update.interval", 28800);

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

@ -574,8 +574,6 @@ nsBrowserContentHandler.prototype = {
get defaultArgs() {
var prefb = Components.classes["@mozilla.org/preferences-service;1"]
.getService(nsIPrefBranch);
var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Components.interfaces.nsIURLFormatter);
var overridePage = "";
var haveUpdateSession = false;
@ -589,7 +587,7 @@ nsBrowserContentHandler.prototype = {
switch (override) {
case OVERRIDE_NEW_PROFILE:
// New profile.
overridePage = formatter.formatURLPref("startup.homepage_welcome_url");
overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
break;
case OVERRIDE_NEW_MSTONE:
// Existing profile, new milestone build.
@ -600,12 +598,19 @@ nsBrowserContentHandler.prototype = {
var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"]
.getService(Components.interfaces.nsISessionStartup);
haveUpdateSession = ss.doRestore();
overridePage = formatter.formatURLPref("startup.homepage_override_url");
overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
if (prefb.prefHasUserValue("app.update.postupdate"))
overridePage = getPostUpdateOverridePage(overridePage);
break;
}
}
else {
// No need to override homepage, but update snippets url if the pref has
// been manually changed.
if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
AboutHomeUtils.loadSnippetsURL();
}
}
} catch (ex) {}
// formatURLPref might return "about:blank" if getting the pref fails
@ -882,6 +887,7 @@ nsDefaultCommandLineHandler.prototype = {
};
let AboutHomeUtils = {
SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
get _storage() {
let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
@ -908,10 +914,10 @@ let AboutHomeUtils = {
loadSnippetsURL: function AHU_loadSnippetsURL()
{
const STARTPAGE_VERSION = 1;
const SNIPPETS_URL = "http://snippets.mozilla.com/" + STARTPAGE_VERSION + "/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/";
let updateURL = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"].
getService(Components.interfaces.nsIURLFormatter).
formatURL(SNIPPETS_URL);
let updateURL = Services.prefs
.getCharPref(this.SNIPPETS_URL_PREF)
.replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
updateURL = Services.urlFormatter.formatURL(updateURL);
this._storage.setItem("snippets-update-url", updateURL);
},
};

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

@ -499,10 +499,10 @@ PlacesViewBase.prototype = {
// Many users consider toolbars as shortcuts containers, so explicitly
// allow empty labels on toolbarbuttons. For any other element try to be
// smarter, guessing a title from the uri.
elt.label = PlacesUIUtils.getBestTitle(aPlacesNode);
elt.setAttribute("label", PlacesUIUtils.getBestTitle(aPlacesNode));
}
else {
elt.label = aNewTitle;
elt.setAttribute("label", aNewTitle);
}
},

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

@ -720,7 +720,7 @@ var PlacesUIUtils = {
* This is actually used to distinguish user-initiated visits in frames
* so automatic visits can be correctly ignored.
*/
markPageAsFollowedLink: function PUIU_markPageAsUserClicked(aURL) {
markPageAsFollowedLink: function PUIU_markPageAsFollowedLink(aURL) {
PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory)
.markPageAsFollowedLink(this.createFixedURI(aURL));
},

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

@ -65,6 +65,10 @@ _BROWSER_TEST_FILES = \
browser_views_liveupdate.js \
browser_sidebarpanels_click.js \
browser_library_infoBox.js \
browser_markPageAsFollowedLink.js \
framedPage.html \
frameLeft.html \
frameRight.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Tests that visits across frames are correctly represented in the database.
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const BASE_URL = "http://mochi.test:8888/browser/browser/components/places/tests/browser";
const PAGE_URL = BASE_URL + "/framedPage.html";
const LEFT_URL = BASE_URL + "/frameLeft.html";
const RIGHT_URL = BASE_URL + "/frameRight.html";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
let gTabLoaded = false;
let gLeftFrameVisited = false;
let observer = {
observe: function(aSubject, aTopic, aData)
{
let url = aSubject.QueryInterface(Ci.nsIURI).spec;
if (url == LEFT_URL ) {
is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_EMBED,
"Frames should get a EMBED transition.");
gLeftFrameVisited = true;
maybeClickLink();
}
else if (url == RIGHT_URL ) {
is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_FRAMED_LINK,
"User activated visits should get a FRAMED_LINK transition.");
finish();
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
Services.obs.addObserver(observer, "uri-visit-saved", false);
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(PAGE_URL);
let frameCount = 0;
gBrowser.selectedTab.linkedBrowser.addEventListener("DOMContentLoaded",
function (event)
{
// Wait for all the frames.
if (frameCount++ < 2)
return;
gBrowser.selectedTab.linkedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, false)
gTabLoaded = true;
maybeClickLink();
}, false
);
}
function maybeClickLink() {
if (gTabLoaded && gLeftFrameVisited) {
// Click on the link in the left frame to cause a page load in the
// right frame.
EventUtils.sendMouseEvent({type: "click"}, "clickme", content.frames[0]);
}
}
function getTransitionForUrl(aUrl)
{
let dbConn = PlacesUtils.history
.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
let stmt = dbConn.createStatement(
"SELECT visit_type FROM moz_historyvisits_view WHERE place_id = " +
"(SELECT id FROM moz_places_view WHERE url = :page_url)");
stmt.params.page_url = aUrl;
try {
ok(stmt.executeStep(), "Found the visit in the database");
return stmt.row.visit_type;
}
finally {
stmt.finalize();
}
}
registerCleanupFunction(function ()
{
gBrowser.removeTab(gBrowser.selectedTab);
Services.obs.removeObserver(observer, "uri-visit-saved");
})

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

@ -291,8 +291,8 @@ var bookmarksObserver = {
}
else {
if (!aNewValue && aElementOrTreeIndex.localName != "toolbarbutton")
return aElementOrTreeIndex.label == PlacesUIUtils.getBestTitle(aElementOrTreeIndex._placesNode);
return aElementOrTreeIndex.label == aNewValue;
return aElementOrTreeIndex.getAttribute("label") == PlacesUIUtils.getBestTitle(aElementOrTreeIndex._placesNode);
return aElementOrTreeIndex.getAttribute("label") == aNewValue;
}
};

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

@ -0,0 +1,8 @@
<html>
<head>
<title>Left frame</title>
</head>
<body>
<a id="clickme" href="frameRight.html" target="right">Open page in the right frame.</a>
</body>
</html>

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

@ -0,0 +1,8 @@
<html>
<head>
<title>Right Frame</title>
</head>
<body>
This is the right frame.
</body>
</html>

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

@ -0,0 +1,9 @@
<html>
<head>
<title>Framed page</title>
</head>
<frameset cols="*,*">
<frame name="left" src="frameLeft.html">
<frame name="right" src="about:robots">
</frameset>
</html>

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

@ -45,12 +45,10 @@
%globalDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
#ifdef XP_WIN
<!ENTITY basePBMenu.label "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
#elifdef XP_MACOSX
#ifdef XP_MACOSX
<!ENTITY basePBMenu.label "&toolsMenu.label;">
#else
<!ENTITY basePBMenu.label "<span class='appMenuButton'>&appMenuButton.label;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
<!ENTITY basePBMenu.label "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
#endif
<!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
%privatebrowsingpageDTD;

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

@ -52,14 +52,14 @@
<menuitem id="menu_HelpPopup_reportPhishingtoolmenu"
label="&reportPhishSiteMenu.title2;"
accesskey="&reportPhishSiteMenu.accesskey;"
insertbefore="updateSeparator"
insertbefore="aboutSeparator"
observes="reportPhishingBroadcaster"
oncommand="openUILink(safebrowsing.getReportURL('Phish'), event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu"
label="&safeb.palm.notforgery.label2;"
accesskey="&reportPhishSiteMenu.accesskey;"
insertbefore="updateSeparator"
insertbefore="aboutSeparator"
observes="reportPhishingErrorBroadcaster"
oncommand="openUILinkIn(safebrowsing.getReportURL('Error'), 'tab');"
onclick="checkForMiddleClick(this, event);"/>

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

@ -605,7 +605,7 @@
element.setAttribute("label", label);
element.setAttribute("anonid", "paste-and-search");
element.setAttribute("oncommand",
"BrowserSearch.searchBar.value = ''; goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
"BrowserSearch.searchBar.select(); goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
cxmenu.insertBefore(element, insertLocation.nextSibling);
pasteAndSearch = element;
}

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

@ -260,10 +260,7 @@ var WinTaskbarJumpList =
_pendingStatements: {},
_hasPendingStatements: function WTBJL__hasPendingStatements() {
for (let listType in this._pendingStatements) {
return true;
}
return false;
return Object.keys(this._pendingStatements).length > 0;
},
_buildList: function WTBJL__buildList() {
@ -344,6 +341,11 @@ var WinTaskbarJumpList =
},
_buildFrequent: function WTBJL__buildFrequent() {
// If history is empty, just bail out.
if (!PlacesUtils.history.hasHistoryEntries) {
return;
}
// 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
@ -377,6 +379,11 @@ var WinTaskbarJumpList =
},
_buildRecent: function WTBJL__buildRecent() {
// If history is empty, just bail out.
if (!PlacesUtils.history.hasHistoryEntries) {
return;
}
var items = Cc["@mozilla.org/array;1"].
createInstance(Ci.nsIMutableArray);
// Frequent items will be skipped, so we select a double amount of

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

@ -213,6 +213,7 @@
@BINPATH@/components/necko_strconv.xpt
@BINPATH@/components/necko_viewsource.xpt
@BINPATH@/components/necko_wifi.xpt
@BINPATH@/components/necko_wyciwyg.xpt
@BINPATH@/components/necko.xpt
@BINPATH@/components/loginmgr.xpt
@BINPATH@/components/parentalcontrols.xpt

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

@ -355,8 +355,16 @@ toolbar:not([mode="icons"]) #restore-button {
opacity: .4;
}
.toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png);
}
.toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
-moz-margin-end: 1px;
}
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
width: 14px;
padding-top: 2px;
-moz-border-start: none !important;
@ -1937,7 +1945,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
}
#notification-popup {
color: #fff;
margin-left: -16px;
margin-right: -16px;
}

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

@ -1864,7 +1864,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
}
.geolocation-text-link {
padding-top: 5px;
margin-top: 17px;
}
.popup-notification-icon[popupid="xpinstall-disabled"],

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

@ -360,6 +360,7 @@ user_pref("network.http.prompt-temp-redirect", false);
user_pref("media.cache_size", 100);
user_pref("security.warn_viewing_mixed", false);
user_pref("app.update.enabled", false);
user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
// Only load extensions from the application and user profile
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION

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

@ -115,10 +115,18 @@ def checkForCrashes(dumpDir, symbolsPath, testName=None):
for d in dumps:
log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
nullfd = open(os.devnull, 'w')
# eat minidump_stackwalk errors
subprocess.call([stackwalkPath, d, symbolsPath], stderr=nullfd)
nullfd.close()
p = subprocess.Popen([stackwalkPath, d, symbolsPath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, err) = p.communicate()
if len(out) > 3:
# minidump_stackwalk is chatty, so ignore stderr when it succeeds.
print out
else:
print "stderr from minidump_stackwalk:"
print err
if p.returncode != 0:
print "minidump_stackwalk exited with return code %d" % p.returncode
elif stackwalkCGI and symbolsPath and isURL(symbolsPath):
f = None
try:
@ -131,7 +139,11 @@ def checkForCrashes(dumpDir, symbolsPath, testName=None):
datagen, headers = multipart_encode({"minidump": f,
"symbols": symbolsPath})
request = urllib2.Request(stackwalkCGI, datagen, headers)
print urllib2.urlopen(request).read()
result = urllib2.urlopen(request).read()
if len(result) > 3:
print result
else:
print "stackwalkCGI returned nothing."
finally:
if f:
f.close()

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

@ -44,6 +44,7 @@ See the documentation for jar.mn on MDC for further details on the format.
import sys
import os
import os.path
import errno
import re
import logging
from time import localtime
@ -445,7 +446,7 @@ class JarMaker(object):
try:
os.remove(out)
except OSError, e:
if e.errno != 2:
if e.errno != errno.ENOENT:
raise
return open(out, 'wb')
def ensureDirFor(self, name):
@ -465,7 +466,7 @@ class JarMaker(object):
try:
os.remove(out)
except OSError, e:
if e.errno != 2:
if e.errno != errno.ENOENT:
raise
os.symlink(src, out)

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

@ -165,7 +165,11 @@ MOZ_TREMOR = @MOZ_TREMOR@
MOZ_WEBM = @MOZ_WEBM@
VPX_AS = @VPX_AS@
VPX_ASFLAGS = @VPX_ASFLAGS@
VPX_DASH_C_FLAG = @VPX_DASH_C_FLAG@
VPX_AS_CONVERSION = @VPX_AS_CONVERSION@
VPX_ASM_SUFFIX = @VPX_ASM_SUFFIX@
VPX_X86_ASM = @VPX_X86_ASM@
VPX_ARM_ASM = @VPX_ARM_ASM@
NS_PRINTING = @NS_PRINTING@
MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@

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

@ -234,7 +234,7 @@ endif
#
ifdef NS_TRACE_MALLOC
MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF -OPT:nowin98
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF
endif # NS_TRACE_MALLOC
endif # MOZ_DEBUG

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

@ -59,15 +59,13 @@
#define MODULE(_name) \
NSMODULE_NAME(_name),
&NSMODULE_NAME(_name),
/**
* The nsStaticModuleInfo
*/
static const mozilla::Module *const kStaticModules[] = {
const mozilla::Module *const *const kPStaticModules[] = {
%MODULE_LIST%
#line 70 "nsStaticComponents.cpp.in"
NULL
};
mozilla::Module const *const *const kPStaticModules = kStaticModules;

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

@ -43,6 +43,6 @@
// These symbols are provided by nsStaticComponents.cpp, and also by other
// static component providers such as nsStaticXULComponents (libxul).
extern mozilla::Module const *const *const kPStaticModules;
extern mozilla::Module const *const *const kPStaticModules[];
#endif

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

@ -992,7 +992,7 @@ else
AC_MSG_RESULT([yes])
fi
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.6 python2.5 python2.4 python)
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python2.6 python2.5 python)
if test -z "$PYTHON"; then
AC_MSG_ERROR([python was not found in \$PATH])
fi
@ -1846,8 +1846,6 @@ case "$host" in
;;
*cygwin*|*mingw*|*mks*|*msvc*|*wince|*winmo)
# we need Python 2.5 on Windows
PYTHON_VERSION=2.5
if test -n "$_WIN32_MSVC"; then
HOST_AR=lib
HOST_AR_FLAGS='-NOLOGO -OUT:"$@"'
@ -1921,8 +1919,7 @@ case "$host" in
;;
esac
dnl We require version 2.4 or newer of Python to build,
dnl and 2.5 or newer on Windows.
dnl We require version 2.5 or newer of Python to build.
AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
changequote(,)
$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
@ -4726,10 +4723,10 @@ AC_CHECK_PROGS(YASM, yasm, "")
if test -n "$YASM"; then
dnl Pull out yasm's version string
changequote(,)
_YASM_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*|\1|p'
_YASM_VER_FILTER='s|.* \([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\).*|\1|p'
changequote([,])
YASM_VERSION=`yasm --version | sed -nre "$_YASM_VER_FILTER"`
YASM_VERSION=`yasm --version | sed -ne "$_YASM_VER_FILTER"`
_YASM_MAJOR_VERSION=`echo ${YASM_VERSION} | $AWK -F\. '{ print $1 }'`
_YASM_MINOR_VERSION=`echo ${YASM_VERSION} | $AWK -F\. '{ print $2 }'`
_YASM_RELEASE=` echo ${YASM_VERSION} | $AWK -F\. '{ print $3 }'`
@ -4961,7 +4958,11 @@ MOZ_MEDIA=
MOZ_WEBM=1
VPX_AS=
VPX_ASFLAGS=
VPX_AS_DASH_C_FLAG=
VPX_AS_CONVERSION=
VPX_ASM_SUFFIX=
VPX_X86_ASM=
VPX_ARM_ASM=
MOZ_PANGO=1
MOZ_PERMISSIONS=1
MOZ_PLACES=1
@ -6048,8 +6049,10 @@ if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
dnl We currently require yasm on all platforms and require yasm 1.1.0 on Win32.
dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
dnl We currently require gcc on all arm platforms.
VPX_AS=$YASM
VPX_ASM_SUFFIX=asm
dnl See if we have assembly on this platform.
case "$OS_ARCH:$CPU_ARCH" in
@ -6096,6 +6099,17 @@ if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
fi
fi
;;
*:arm*)
if test -n "$GNU_AS" ; then
VPX_AS=$AS
dnl These flags are a lie; they're just used to enable the requisite
dnl opcodes; actual arch detection is done at runtime.
VPX_ASFLAGS="-march=armv7-a -mfpu=neon"
VPX_DASH_C_FLAG="-c"
VPX_AS_CONVERSION="$PERL ${srcdir}/media/libvpx/build/make/ads2gas.pl"
VPX_ASM_SUFFIX="$ASM_SUFFIX"
VPX_ARM_ASM=1
fi
esac
if test -n "$COMPILE_ENVIRONMENT" -a -n "$VPX_X86_ASM" -a -z "$VPX_AS"; then
@ -6104,6 +6118,8 @@ if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
if test -n "$VPX_X86_ASM"; then
AC_DEFINE(VPX_X86_ASM)
elif test -n "$VPX_ARM_ASM"; then
AC_DEFINE(VPX_ARM_ASM)
else
AC_MSG_WARN([No assembler or assembly support for libvpx. Using unoptimized C routines.])
fi
@ -6406,15 +6422,11 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c tridentprofile` -ne 0; then
MOZ_EXTENSIONS="$MOZ_EXTENSIONS tridentprofile"
fi
dnl xforms requires xtf and schema-validation
dnl xforms requires xtf
if test -z "$MOZ_XTF" -a `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0; then
AC_MSG_WARN([Cannot build XForms without XTF support. Removing XForms from MOZ_EXTENSIONS.])
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'`
fi
if test `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0 && test `echo "$MOZ_EXTENSIONS" | grep -c schema-validation` -eq 0; then
AC_MSG_WARN([Cannot build XForms without schema validation. Removing XForms from MOZ_EXTENSIONS.])
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'`
fi
if test `echo "$MOZ_EXTENSIONS" | grep -c auth` -ne 0; then
AC_MSG_WARN([auth is no longer an extension, use --disable-negotiateauth to disable.])
@ -8585,7 +8597,7 @@ if test "$MOZ_TREE_CAIRO"; then
if test "$MOZ_TREE_PIXMAN"; then
MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS"' $(call EXPAND_LIBNAME_PATH,mozlibpixman,$(DEPTH)/gfx/cairo/libpixman/src)'
else
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.3)
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.19.2)
MOZ_CAIRO_CFLAGS="$MOZ_CAIRO_CFLAGS $PIXMAN_CFLAGS"
MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $PIXMAN_LIBS"
fi
@ -9089,7 +9101,11 @@ AC_SUBST(MOZ_OGG)
AC_SUBST(MOZ_ALSA_LIBS)
AC_SUBST(VPX_AS)
AC_SUBST(VPX_ASFLAGS)
AC_SUBST(VPX_DASH_C_FLAG)
AC_SUBST(VPX_AS_CONVERSION)
AC_SUBST(VPX_ASM_SUFFIX)
AC_SUBST(VPX_X86_ASM)
AC_SUBST(VPX_ARM_ASM)
if test "$USING_HCC"; then
CC='${topsrcdir}/build/hcc'

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

@ -121,8 +121,8 @@ class Element;
#define NS_IDOCUMENT_IID \
{ 0x7fb1e97d, 0xbd2c, 0x47cf, \
{ 0xa3, 0x05, 0x5b, 0x31, 0xd4, 0x1d, 0x3a, 0x52 } }
{ 0xc38a7935, 0xc854, 0x4df7, \
{ 0x8f, 0xd4, 0xa2, 0x6f, 0x0d, 0x27, 0x9f, 0x31 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -1280,6 +1280,11 @@ public:
virtual nsSMILAnimationController* GetAnimationController() = 0;
#endif // MOZ_SMIL
// Makes the images on this document capable of having their animation
// active or suspended. An Image will animate as long as at least one of its
// owning Documents needs it to animate; otherwise it can suspend.
virtual void SetImagesNeedAnimating(PRBool aAnimating) = 0;
/**
* Prevents user initiated events from being dispatched to the document and
* subdocuments.

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

@ -85,7 +85,6 @@ var gPrefObserver = {
function CSPWarning(aMsg) {
var textMessage = 'CSP WARN: ' + aMsg + "\n";
dump(textMessage);
var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
.createInstance(Components.interfaces.nsIScriptError);
@ -99,7 +98,6 @@ function CSPWarning(aMsg) {
function CSPError(aMsg) {
var textMessage = 'CSP ERROR: ' + aMsg + "\n";
dump(textMessage);
var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
.createInstance(Components.interfaces.nsIScriptError);
@ -115,7 +113,6 @@ function CSPdebug(aMsg) {
if (!gPrefObserver.debugEnabled) return;
aMsg = 'CSP debug: ' + aMsg + "\n";
dump(aMsg);
Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService)
.logStringMessage(aMsg);

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

@ -5543,6 +5543,11 @@ nsDocument::GetAnimationController()
}
}
// If we're hidden (or being hidden), notify the animation controller.
if (!mIsShowing) {
mAnimationController->OnPageHide();
}
return mAnimationController;
}
#endif // MOZ_SMIL

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

@ -919,6 +919,8 @@ public:
nsSMILAnimationController* GetAnimationController();
#endif // MOZ_SMIL
void SetImagesNeedAnimating(PRBool aAnimating);
virtual void SuppressEventHandling(PRUint32 aIncrease);
virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents);
@ -1252,12 +1254,6 @@ private:
protected:
PRBool mWillReparent;
#endif
protected:
// Makes the images on this document capable of having their animation
// active or suspended. An Image will animate as long as at least one of its
// owning Documents needs it to animate; otherwise it can suspend.
void SetImagesNeedAnimating(PRBool aAnimating);
};
#define NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class) \

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

@ -105,34 +105,45 @@ nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
if (!doc)
return;
// This will be the URI of the document the content belongs to
// (the URI of the XBL document if the content is anonymous
// XBL content)
nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
nsIContent* bindingParent = aFromContent->GetBindingParent();
PRBool isXBL = PR_FALSE;
if (bindingParent) {
nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
if (binding) {
// XXX sXBL/XBL2 issue
// If this is an anonymous XBL element then the URI is
// relative to the binding document. A full fix requires a
// proper XBL2 implementation but for now URIs that are
// relative to the binding document should be resolve to the
// copy of the target element that has been inserted into the
// bound document.
documentURL = do_QueryInterface(binding->PrototypeBinding()->DocURI());
isXBL = PR_TRUE;
nsCOMPtr<nsIURL> bindingDocumentURL =
do_QueryInterface(binding->PrototypeBinding()->DocURI());
if (EqualExceptRef(url, bindingDocumentURL)) {
// XXX sXBL/XBL2 issue
// Our content is an anonymous XBL element from a binding inside the
// same document that the referenced URI points to. In order to avoid
// the risk of ID collisions we restrict ourselves to anonymous
// elements from this binding; specifically, URIs that are relative to
// the binding document should resolve to the copy of the target
// element that has been inserted into the bound document.
// If the URI points to a different document we don't need this
// restriction.
nsINodeList* anonymousChildren =
doc->BindingManager()->GetAnonymousNodesFor(bindingParent);
if (anonymousChildren) {
PRUint32 length;
anonymousChildren->GetLength(&length);
for (PRUint32 i = 0; i < length && !mElement; ++i) {
mElement =
nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref);
}
}
// We don't have watching working yet for XBL, so bail out here.
return;
}
}
}
nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
if (!documentURL)
return;
if (!EqualExceptRef(url, documentURL)) {
// Don't take the XBL codepath here, since we'll want to just
// normally set up our external resource document and then watch
// it as needed.
isXBL = PR_FALSE;
nsRefPtr<nsIDocument::ExternalResourceLoad> load;
doc = doc->RequestExternalResource(url, aFromContent, getter_AddRefs(load));
if (!doc) {
@ -151,24 +162,6 @@ nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
}
}
// Get the element
if (isXBL) {
nsINodeList* anonymousChildren =
doc->BindingManager()-> GetAnonymousNodesFor(bindingParent);
if (anonymousChildren) {
PRUint32 length;
anonymousChildren->GetLength(&length);
for (PRUint32 i = 0; i < length && !mElement; ++i) {
mElement =
nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref);
}
}
// We don't have watching working yet for XBL, so bail out here.
return;
}
if (aWatch) {
nsCOMPtr<nsIAtom> atom = do_GetAtom(ref);
if (!atom)

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

@ -343,10 +343,10 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
if (forceOSMesa) {
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (!gl || !InitAndValidateGL()) {
LogMessage("WebGL: OSMesa forced, but creating context failed -- aborting!");
LogMessage("OSMesa forced, but creating context failed -- aborting!");
return NS_ERROR_FAILURE;
}
LogMessage("WebGL: Using software rendering via OSMesa (THIS WILL BE SLOW)");
LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
}
#ifdef XP_WIN
@ -399,8 +399,18 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
}
#endif
// finally, try OSMesa
if (!gl) {
LogMessage("WebGL: Can't get a usable WebGL context");
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (!gl || !InitAndValidateGL()) {
gl = nsnull;
} else {
LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
}
}
if (!gl) {
LogMessage("Can't get a usable WebGL context");
return NS_ERROR_FAILURE;
}

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

@ -474,10 +474,7 @@ protected:
WebGLObjectRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
WebGLObjectRefPtr<WebGLProgram> mCurrentProgram;
// XXX these 3 are wrong types, and aren't used atm (except for the length of the attachments)
nsTArray<WebGLObjectRefPtr<WebGLTexture> > mFramebufferColorAttachments;
nsRefPtr<WebGLFramebuffer> mFramebufferDepthAttachment;
nsRefPtr<WebGLFramebuffer> mFramebufferStencilAttachment;
PRUint32 mMaxFramebufferColorAttachments;
nsRefPtr<WebGLFramebuffer> mBoundFramebuffer;
nsRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
@ -510,6 +507,7 @@ public:
void LogMessageIfVerbose(const char *fmt, va_list ap);
friend class WebGLTexture;
friend class WebGLFramebuffer;
};
// this class is a mixin for the named type wrappers, and is used
@ -1003,12 +1001,14 @@ public:
if (!areAllLevel0ImagesDefined) {
if (mTarget == LOCAL_GL_TEXTURE_2D) {
mContext->LogMessage("We are currently drawing stuff, but some 2D texture has not yet been "
"uploaded any image at level 0. Until it's uploaded, this texture will look black.");
mContext->LogMessageIfVerbose(
"We are currently drawing stuff, but some 2D texture has not yet been "
"uploaded any image at level 0. Until it's uploaded, this texture will look black.");
} else {
mContext->LogMessage("We are currently drawing stuff, but some cube map texture has not yet been "
"uploaded any image at level 0, for at least one of its six faces. "
"Until it's uploaded, this texture will look black.");
mContext->LogMessageIfVerbose(
"We are currently drawing stuff, but some cube map texture has not yet been "
"uploaded any image at level 0, for at least one of its six faces. "
"Until it's uploaded, this texture will look black.");
}
mFakeBlackStatus = DoNeedFakeBlack;
return PR_TRUE;
@ -1234,6 +1234,7 @@ public:
mMapUniformLocations.Clear();
return PR_TRUE;
}
already_AddRefed<WebGLUniformLocation> GetUniformLocationObject(GLint glLocation);
@ -1265,6 +1266,54 @@ protected:
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLProgram, WEBGLPROGRAM_PRIVATE_IID)
#define WEBGLRENDERBUFFER_PRIVATE_IID \
{0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
class WebGLRenderbuffer :
public nsIWebGLRenderbuffer,
public WebGLZeroingObject,
public WebGLRectangleObject,
public WebGLContextBoundObject
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
WebGLRenderbuffer(WebGLContext *context, WebGLuint name, WebGLuint secondBufferName = 0) :
WebGLContextBoundObject(context),
mName(name),
mInternalFormat(0),
mDeleted(PR_FALSE), mInitialized(PR_FALSE)
{ }
void Delete() {
if (mDeleted)
return;
ZeroOwners();
mDeleted = PR_TRUE;
}
PRBool Deleted() const { return mDeleted; }
WebGLuint GLName() const { return mName; }
PRBool Initialized() const { return mInitialized; }
void SetInitialized(PRBool aInitialized) { mInitialized = aInitialized; }
WebGLenum InternalFormat() const { return mInternalFormat; }
void SetInternalFormat(WebGLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLRENDERBUFFER
protected:
WebGLuint mName;
WebGLenum mInternalFormat;
PRBool mDeleted;
PRBool mInitialized;
friend class WebGLFramebuffer;
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
#define WEBGLFRAMEBUFFER_PRIVATE_IID \
{0x0052a16f, 0x4bc9, 0x4a55, {0x9d, 0xa3, 0x54, 0x95, 0xaa, 0x4e, 0x80, 0xb9}}
class WebGLFramebuffer :
@ -1278,7 +1327,10 @@ public:
WebGLFramebuffer(WebGLContext *context, WebGLuint name) :
WebGLContextBoundObject(context),
mName(name), mDeleted(PR_FALSE)
mName(name), mDeleted(PR_FALSE),
mHasDepthAttachment(PR_FALSE),
mHasStencilAttachment(PR_FALSE),
mHasDepthStencilAttachment(PR_FALSE)
{ }
void Delete() {
@ -1290,49 +1342,285 @@ public:
PRBool Deleted() { return mDeleted; }
WebGLuint GLName() { return mName; }
nsresult FramebufferRenderbuffer(WebGLenum target,
WebGLenum attachment,
WebGLenum rbtarget,
nsIWebGLRenderbuffer *rbobj)
{
WebGLuint renderbuffername;
PRBool isNull;
WebGLRenderbuffer *wrb;
if (!mContext->GetConcreteObjectAndGLName("framebufferRenderbuffer: renderbuffer",
rbobj, &wrb, &renderbuffername, &isNull))
{
return NS_OK;
}
if (target != LOCAL_GL_FRAMEBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
if (rbtarget != LOCAL_GL_RENDERBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
const char *badAttachmentFormatMsg =
"framebufferRenderbuffer: this renderbuffer does not have a suitable format for this attachment point";
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
if (!isNull) {
if (wrb->mInternalFormat != LOCAL_GL_DEPTH_COMPONENT16)
return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
}
mDepthOrStencilRenderbufferAttachment = wrb;
mHasDepthAttachment = !isNull;
break;
case LOCAL_GL_STENCIL_ATTACHMENT:
if (!isNull) {
if (wrb->mInternalFormat != LOCAL_GL_STENCIL_INDEX8)
return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
}
mDepthOrStencilRenderbufferAttachment = wrb;
mHasStencilAttachment = !isNull;
break;
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
if (!isNull) {
if (wrb->mInternalFormat != LOCAL_GL_DEPTH_STENCIL)
return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
}
mDepthOrStencilRenderbufferAttachment = wrb;
mHasDepthStencilAttachment = !isNull;
break;
default:
// finish checking that the 'attachment' parameter is among the allowed values
if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mMaxFramebufferColorAttachments))
{
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
}
if (!isNull) {
if (wrb->mInternalFormat != LOCAL_GL_RGBA4 &&
wrb->mInternalFormat != LOCAL_GL_RGB565 &&
wrb->mInternalFormat != LOCAL_GL_RGB5_A1)
{
return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
}
}
mColorRenderbufferAttachment = wrb;
break;
}
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
setDimensions(wrb);
mContext->MakeContextCurrent();
mContext->gl->fFramebufferRenderbuffer(target, attachment, rbtarget, renderbuffername);
return NS_OK;
}
nsresult FramebufferTexture2D(WebGLenum target,
WebGLenum attachment,
WebGLenum textarget,
nsIWebGLTexture *tobj,
WebGLint level)
{
WebGLuint texturename;
PRBool isNull;
WebGLTexture *wtex;
if (!mContext->GetConcreteObjectAndGLName("framebufferTexture2D: texture",
tobj, &wtex, &texturename, &isNull))
{
return NS_OK;
}
if (target != LOCAL_GL_FRAMEBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
if (!isNull && textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
if (!isNull && level > 0)
return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
return mContext->ErrorInvalidOperation("framebufferTexture2D: depth and stencil attachments can "
"only be renderbuffers, not textures, as there is no suitable texture format.");
break;
default:
if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mMaxFramebufferColorAttachments))
{
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
}
// nothing to do for color buffers. all textures have a color-renderable format.
break;
}
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
setDimensions(wtex);
mContext->MakeContextCurrent();
mContext->gl->fFramebufferTexture2D(target, attachment, textarget, texturename, level);
return NS_OK;
}
// implement inline, as it's performance critical (called by draw-functions).
// the generic case for which we're optimizing is the case where there's nothing to initialize.
inline PRBool CheckAndInitializeRenderbuffers()
{
if (HasConflictingAttachments()) {
mContext->SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
return PR_FALSE;
}
if ((mColorRenderbufferAttachment && !mColorRenderbufferAttachment->Initialized()) ||
(mDepthOrStencilRenderbufferAttachment && !mDepthOrStencilRenderbufferAttachment->Initialized()))
{
InitializeRenderbuffers();
}
return PR_TRUE;
}
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLFRAMEBUFFER
PRBool HasConflictingAttachments() const {
return int(mHasDepthAttachment) +
int(mHasStencilAttachment) +
int(mHasDepthStencilAttachment) > 1;
}
protected:
// protected because WebGLContext should only call InitializeRenderbuffers
void InitializeRenderbuffers()
{
mContext->MakeContextCurrent();
if (mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return;
PRBool initializeColorBuffer = mColorRenderbufferAttachment &&
!mColorRenderbufferAttachment->Initialized();
PRBool initializeDepthOrStencilBuffer = mDepthOrStencilRenderbufferAttachment &&
!mDepthOrStencilRenderbufferAttachment->Initialized();
PRBool initializeDepthBuffer = initializeDepthOrStencilBuffer && HasDepthBuffer();
PRBool initializeStencilBuffer = initializeDepthOrStencilBuffer && HasStencilBuffer();
realGLboolean savedColorMask[] = {0}, savedDepthMask = 0;
GLuint savedStencilMask = 0;
GLfloat savedColorClearValue[] = {0.f}, savedDepthClearValue = 0.f;
GLint savedStencilClearValue = 0;
GLuint clearBits = 0;
realGLboolean wasScissorTestEnabled = mContext->gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST);
mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
realGLboolean wasDitherEnabled = mContext->gl->fIsEnabled(LOCAL_GL_DITHER);
mContext->gl->fDisable(LOCAL_GL_DITHER);
mContext->gl->PushViewportRect(nsIntRect(0,0,width(),height()));
if (initializeColorBuffer) {
mContext->gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, savedColorMask);
mContext->gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, savedColorClearValue);
mContext->gl->fColorMask(1, 1, 1, 1);
mContext->gl->fClearColor(0.f, 0.f, 0.f, 0.f);
clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
}
if (initializeDepthBuffer) {
mContext->gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &savedDepthMask);
mContext->gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &savedDepthClearValue);
mContext->gl->fDepthMask(1);
mContext->gl->fClearDepth(0.f);
clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
}
if (initializeStencilBuffer) {
mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, reinterpret_cast<GLint*>(&savedStencilMask));
mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &savedStencilClearValue);
mContext->gl->fStencilMask(0xffffffff);
mContext->gl->fClearStencil(0);
clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
}
// the one useful line of code
mContext->gl->fClear(clearBits);
if (initializeColorBuffer) {
mContext->gl->fColorMask(savedColorMask[0],
savedColorMask[1],
savedColorMask[2],
savedColorMask[3]);
mContext->gl->fClearColor(savedColorClearValue[0],
savedColorClearValue[1],
savedColorClearValue[2],
savedColorClearValue[3]);
mColorRenderbufferAttachment->SetInitialized(PR_TRUE);
}
if (initializeDepthBuffer) {
mContext->gl->fDepthMask(savedDepthMask);
mContext->gl->fClearDepth(savedDepthClearValue);
mDepthOrStencilRenderbufferAttachment->SetInitialized(PR_TRUE);
}
if (initializeStencilBuffer) {
mContext->gl->fStencilMask(savedStencilMask);
mContext->gl->fClearStencil(savedStencilClearValue);
mDepthOrStencilRenderbufferAttachment->SetInitialized(PR_TRUE);
}
mContext->gl->PopViewportRect();
if (wasDitherEnabled)
mContext->gl->fEnable(LOCAL_GL_DITHER);
else
mContext->gl->fDisable(LOCAL_GL_DITHER);
if (wasScissorTestEnabled)
mContext->gl->fEnable(LOCAL_GL_DITHER);
else
mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
}
PRBool HasDepthBuffer() const {
return mHasDepthAttachment || mHasDepthStencilAttachment;
}
PRBool HasStencilBuffer() const {
return mHasStencilAttachment || mHasDepthStencilAttachment;
}
WebGLuint mName;
PRBool mDeleted;
// we only store pointers to attached renderbuffers, not to attached textures, because
// we will only need to initialize renderbuffers. Textures are already initialized.
nsRefPtr<WebGLRenderbuffer> mColorRenderbufferAttachment;
nsRefPtr<WebGLRenderbuffer> mDepthOrStencilRenderbufferAttachment;
// these boolean values keep track of all attachments: renderbuffers and textures.
// thus they are not at all redundant with the above member pointers.
PRBool mHasDepthAttachment;
PRBool mHasStencilAttachment;
PRBool mHasDepthStencilAttachment;
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLFramebuffer, WEBGLFRAMEBUFFER_PRIVATE_IID)
#define WEBGLRENDERBUFFER_PRIVATE_IID \
{0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
class WebGLRenderbuffer :
public nsIWebGLRenderbuffer,
public WebGLZeroingObject,
public WebGLRectangleObject,
public WebGLContextBoundObject
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
WebGLRenderbuffer(WebGLContext *context, WebGLuint name) :
WebGLContextBoundObject(context),
mName(name), mDeleted(PR_FALSE)
{ }
void Delete() {
if (mDeleted)
return;
ZeroOwners();
mDeleted = PR_TRUE;
}
PRBool Deleted() { return mDeleted; }
WebGLuint GLName() { return mName; }
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLRENDERBUFFER
protected:
WebGLuint mName;
PRBool mDeleted;
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
#define WEBGLUNIFORMLOCATION_PRIVATE_IID \
{0x01a8a614, 0xb109, 0x42f1, {0xb4, 0x40, 0x8d, 0x8b, 0x87, 0x0b, 0x43, 0xa7}}
class WebGLUniformLocation :

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

@ -349,7 +349,7 @@ NS_IMETHODIMP
WebGLContext::BufferData(PRInt32 dummy)
{
// this should never be called
LogMessage("BufferData");
LogMessageIfVerbose("BufferData");
return NS_ERROR_FAILURE;
}
@ -522,9 +522,13 @@ WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
MakeContextCurrent();
if (target != LOCAL_GL_FRAMEBUFFER)
return ErrorInvalidEnum("CheckFramebufferStatus: target must be FRAMEBUFFER");
return ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
if (mBoundFramebuffer && mBoundFramebuffer->HasConflictingAttachments())
*retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
else
*retval = gl->fCheckFramebufferStatus(target);
*retval = gl->fCheckFramebufferStatus(target);
return NS_OK;
}
@ -532,6 +536,10 @@ NS_IMETHODIMP
WebGLContext::Clear(PRUint32 mask)
{
MakeContextCurrent();
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return NS_OK;
gl->fClear(mask);
Invalidate();
@ -760,6 +768,7 @@ WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj)
*/
gl->fDeleteRenderbuffers(1, &rbufname);
rbuf->Delete();
mMapRenderbuffers.Remove(rbufname);
@ -1047,6 +1056,9 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
MakeContextCurrent();
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return NS_OK;
BindFakeBlackTextures();
DoFakeVertexAttrib0(checked_firstPlusCount.value());
@ -1124,6 +1136,9 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
MakeContextCurrent();
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return NS_OK;
BindFakeBlackTextures();
DoFakeVertexAttrib0(checked_neededCount.value());
@ -1171,43 +1186,13 @@ WebGLContext::EnableVertexAttribArray(WebGLuint index)
return NS_OK;
}
// XXX need to track this -- see glDeleteRenderbuffer above and man page for DeleteRenderbuffers
NS_IMETHODIMP
WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, nsIWebGLRenderbuffer *rbobj)
{
WebGLuint renderbuffername;
PRBool isNull;
WebGLRenderbuffer *wrb;
if (!GetConcreteObjectAndGLName("framebufferRenderbuffer: renderbuffer", rbobj, &wrb, &renderbuffername, &isNull))
return NS_OK;
if (target != LOCAL_GL_FRAMEBUFFER)
return ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mFramebufferColorAttachments.Length()) &&
attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
attachment != LOCAL_GL_STENCIL_ATTACHMENT)
{
return ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
}
if (rbtarget != LOCAL_GL_RENDERBUFFER)
return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
if (!mBoundFramebuffer)
return ErrorInvalidOperation("FramebufferRenderbuffer: cannot modify framebuffer 0");
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wrb);
MakeContextCurrent();
gl->fFramebufferRenderbuffer(target, attachment, rbtarget, renderbuffername);
return NS_OK;
if (mBoundFramebuffer)
return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, rbobj);
else
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
}
NS_IMETHODIMP
@ -1217,44 +1202,10 @@ WebGLContext::FramebufferTexture2D(WebGLenum target,
nsIWebGLTexture *tobj,
WebGLint level)
{
WebGLuint texturename;
PRBool isNull;
WebGLTexture *wtex;
if (!GetConcreteObjectAndGLName("framebufferTexture2D: texture", tobj, &wtex, &texturename, &isNull))
return NS_OK;
if (target != LOCAL_GL_FRAMEBUFFER)
return ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mFramebufferColorAttachments.Length()) &&
attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
attachment != LOCAL_GL_STENCIL_ATTACHMENT)
return ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
if (level != 0)
return ErrorInvalidValue("FramebufferTexture2D: level must be 0");
if (!mBoundFramebuffer)
return ErrorInvalidOperation("FramebufferTexture2D: cannot modify framebuffer 0");
// dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
mBoundFramebuffer->setDimensions(wtex);
// XXXXX we need to store/reference this attachment!
MakeContextCurrent();
gl->fFramebufferTexture2D(target, attachment, textarget, texturename, level);
return NS_OK;
if (mBoundFramebuffer)
return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
else
return ErrorInvalidOperation("framebufferTexture2D: cannot modify framebuffer 0");
}
GL_SAME_METHOD_0(Flush, Flush)
@ -2540,8 +2491,6 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
return ErrorInvalidEnumInfo("ReadPixels: type", type);
}
MakeContextCurrent();
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
PRUint32 packAlignment = mPixelStorePackAlignment;
@ -2559,6 +2508,12 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
if (checked_neededByteLength.value() > byteLength)
return ErrorInvalidOperation("ReadPixels: buffer too small");
MakeContextCurrent();
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return NS_OK;
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) {
// the easy case: we're not reading out-of-range pixels
gl->fReadPixels(x, y, width, height, format, type, data);
@ -2645,32 +2600,57 @@ WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsize
NS_IMETHODIMP
WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height)
{
if (target != LOCAL_GL_RENDERBUFFER)
return ErrorInvalidEnumInfo("RenderbufferStorage: target", target);
switch (internalformat) {
case LOCAL_GL_RGBA4:
// XXX case LOCAL_GL_RGB565:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_DEPTH_COMPONENT:
case LOCAL_GL_DEPTH_COMPONENT16:
case LOCAL_GL_STENCIL_INDEX8:
break;
default:
return ErrorInvalidEnumInfo("RenderbufferStorage: internalformat", internalformat);
}
if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
if (target != LOCAL_GL_RENDERBUFFER)
return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
if (width <= 0 || height <= 0)
return ErrorInvalidValue("RenderbufferStorage: width and height must be > 0");
return ErrorInvalidValue("renderbufferStorage: width and height must be > 0");
if (mBoundRenderbuffer)
mBoundRenderbuffer->setDimensions(width, height);
if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
MakeContextCurrent();
gl->fRenderbufferStorage(target, internalformat, width, height);
// now we need to initialize the renderbuffer to 0 as per the thread "about RenderBufferStorage"
// on the public_webgl list
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
WebGLenum internalformatForGL = internalformat;
switch (internalformat) {
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
// 16-bit RGBA formats are not supported on desktop GL
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
break;
case LOCAL_GL_RGB565:
// the RGB565 format is not supported on desktop GL
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
break;
case LOCAL_GL_DEPTH_COMPONENT16:
case LOCAL_GL_STENCIL_INDEX8:
// nothing to do for these ones
break;
case LOCAL_GL_DEPTH_STENCIL:
// this one is available in newer OpenGL (at least since 3.1); will probably become available
// in OpenGL ES 3 (at least it will have some DEPTH_STENCIL) and is the same value that
// is otherwise provided by EXT_packed_depth_stencil and OES_packed_depth_stencil extensions
// which means it's supported on most GL and GL ES systems already.
//
// So we just use it hoping that it's available (perhaps as an extension) and if it's not available,
// we just let the GL generate an error and don't do anything about it ourselves.
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
break;
default:
ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
}
gl->fRenderbufferStorage(target, internalformatForGL, width, height);
mBoundRenderbuffer->SetInternalFormat(internalformat);
mBoundRenderbuffer->setDimensions(width, height);
mBoundRenderbuffer->SetInitialized(PR_FALSE);
return NS_OK;
}
@ -3183,6 +3163,14 @@ WebGLContext::ValidateProgram(nsIWebGLProgram *pobj)
MakeContextCurrent();
#ifdef XP_MACOSX
if (gl->Vendor() == gl::GLContext::VendorNVIDIA) {
LogMessageIfVerbose("validateProgram: implemented as a no-operation "
"on Mac/NVIDIA to work around a driver crash");
return NS_OK;
}
#endif
gl->fValidateProgram(progname);
return NS_OK;
@ -3245,7 +3233,6 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
#if defined(USE_ANGLE)
if (shader->NeedsTranslation() && mShaderValidation) {
ShHandle compiler = 0;
int debugFlags = 0;
ShBuiltInResources resources;
memset(&resources, 0, sizeof(ShBuiltInResources));

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

@ -362,10 +362,6 @@ WebGLContext::InitAndValidateGL()
mBoundElementArrayBuffer = nsnull;
mCurrentProgram = nsnull;
mFramebufferColorAttachments.Clear();
mFramebufferDepthAttachment = nsnull;
mFramebufferStencilAttachment = nsnull;
mBoundFramebuffer = nsnull;
mBoundRenderbuffer = nsnull;
@ -433,7 +429,7 @@ WebGLContext::InitAndValidateGL()
// Always 1 for GLES2
val = 1;
#endif
mFramebufferColorAttachments.SetLength(val);
mMaxFramebufferColorAttachments = val;
#if defined(DEBUG_vladimir) && defined(USE_GLES2)
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*) &val);

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

@ -3,9 +3,6 @@ conformance/constants.html
conformance/context-attributes-alpha-depth-stencil-antialias.html
conformance/context-attributes.html
conformance/context-type-test.html
conformance/framebuffer-object-attachment.html
conformance/get-active-test.html
conformance/gl-enum-tests.html
conformance/gl-get-calls.html
conformance/gl-teximage.html
conformance/glsl-conformance.html
@ -13,10 +10,8 @@ conformance/methods.html
conformance/program-test.html
conformance/read-pixels-pack-alignment.html
conformance/tex-image-and-sub-image-2d-with-video.html
conformance/tex-image-with-format-and-type.html
conformance/tex-image-with-invalid-data.html
conformance/tex-input-validation.html
conformance/texture-active-bind.html
more/conformance/constants.html
more/conformance/getContext.html
more/conformance/quickCheckAPI.html

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

@ -1355,25 +1355,6 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return nsnull;
}
nsresult
nsDOMEvent::ReportWrongPropertyAccessWarning(const char* aPropertyName)
{
nsCOMPtr<nsIDocument> doc(GetDocumentForReport(mEvent));
nsAutoString propertyName, type;
GetType(type);
propertyName.AssignASCII(aPropertyName);
const PRUnichar *strings[] = { propertyName.get(), type.get() };
return nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
"WrongEventPropertyAccessWarning",
strings, NS_ARRAY_LENGTH(strings),
doc ? doc->GetDocumentURI() : nsnull,
EmptyString(), 0, 0,
nsIScriptError::warningFlag,
"DOM Events");
}
NS_IMETHODIMP
nsDOMEvent::GetPreventDefault(PRBool* aReturn)
{

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

@ -225,7 +225,6 @@ protected:
// Internal helper functions
nsresult SetEventType(const nsAString& aEventTypeArg);
already_AddRefed<nsIContent> GetTargetFromFrame();
nsresult ReportWrongPropertyAccessWarning(const char* aPropertyName);
nsEvent* mEvent;
nsRefPtr<nsPresContext> mPresContext;

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

@ -114,14 +114,12 @@ nsDOMKeyboardEvent::GetCharCode(PRUint32* aCharCode)
switch (mEvent->message) {
case NS_KEY_UP:
case NS_KEY_DOWN:
ReportWrongPropertyAccessWarning("charCode");
*aCharCode = 0;
break;
case NS_KEY_PRESS:
*aCharCode = ((nsKeyEvent*)mEvent)->charCode;
break;
default:
ReportWrongPropertyAccessWarning("charCode");
break;
}
return NS_OK;
@ -139,7 +137,6 @@ nsDOMKeyboardEvent::GetKeyCode(PRUint32* aKeyCode)
*aKeyCode = ((nsKeyEvent*)mEvent)->keyCode;
break;
default:
ReportWrongPropertyAccessWarning("keyCode");
*aKeyCode = 0;
break;
}
@ -169,7 +166,6 @@ nsDOMKeyboardEvent::GetWhich(PRUint32* aWhich)
}
break;
default:
ReportWrongPropertyAccessWarning("which");
*aWhich = 0;
break;
}

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

@ -290,8 +290,13 @@ nsUITimerCallback::Notify(nsITimer* aTimer)
if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
gMouseOrKeyboardEventCounter = 0;
obs->NotifyObservers(nsnull, "user-interaction-inactive", nsnull);
if (gUserInteractionTimer) {
gUserInteractionTimer->Cancel();
NS_RELEASE(gUserInteractionTimer);
}
} else {
obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
nsEventStateManager::UpdateUserActivityTimer();
}
mPreviousCount = gMouseOrKeyboardEventCounter;
return NS_OK;
@ -784,19 +789,30 @@ nsEventStateManager::nsEventStateManager()
{
if (sESMInstanceCount == 0) {
gUserInteractionTimerCallback = new nsUITimerCallback();
if (gUserInteractionTimerCallback) {
if (gUserInteractionTimerCallback)
NS_ADDREF(gUserInteractionTimerCallback);
CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
if (gUserInteractionTimer) {
gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
NS_USER_INTERACTION_INTERVAL,
nsITimer::TYPE_REPEATING_SLACK);
}
}
UpdateUserActivityTimer();
}
++sESMInstanceCount;
}
nsresult
nsEventStateManager::UpdateUserActivityTimer(void)
{
if (!gUserInteractionTimerCallback)
return NS_OK;
if (!gUserInteractionTimer)
CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
if (gUserInteractionTimer) {
gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
NS_USER_INTERACTION_INTERVAL,
nsITimer::TYPE_ONE_SHOT);
}
return NS_OK;
}
NS_IMETHODIMP
nsEventStateManager::Init()
{
@ -1071,6 +1087,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
UpdateUserActivityTimer();
}
}
++gMouseOrKeyboardEventCounter;
@ -3014,15 +3031,18 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
if (aEvent->message == NS_MOUSE_PIXEL_SCROLL) {
if (action == MOUSE_SCROLL_N_LINES) {
if (action == MOUSE_SCROLL_N_LINES ||
(msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
action = MOUSE_SCROLL_PIXELS;
} else {
// Do not scroll pixels when zooming
action = -1;
}
} else if (msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
if (action == MOUSE_SCROLL_N_LINES) {
// We shouldn't scroll lines when a pixel scroll event will follow.
if (action == MOUSE_SCROLL_N_LINES ||
(msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
// Don't scroll lines when a pixel scroll event will follow.
// Also, don't do history scrolling or zooming for momentum scrolls.
action = -1;
}
}

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

@ -54,6 +54,8 @@
#include "nsCycleCollectionParticipant.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsIScrollableFrame.h"
#include "nsFocusManager.h"
#include "nsIDocument.h"
class nsIPresShell;
class nsIDocShell;
@ -404,6 +406,9 @@ protected:
PRPackedBool m_haveShutdown;
public:
static nsresult UpdateUserActivityTimer(void);
// Array for accesskey support
nsCOMArray<nsIContent> mAccessKeys;
@ -436,14 +441,25 @@ protected:
class nsAutoHandlingUserInputStatePusher
{
public:
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput, PRBool aIsMouseDown)
: mIsHandlingUserInput(aIsHandlingUserInput), mIsMouseDown(aIsMouseDown)
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput,
nsEvent* aEvent,
nsIDocument* aDocument)
: mIsHandlingUserInput(aIsHandlingUserInput),
mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN),
mResetFMMouseDownState(PR_FALSE)
{
if (aIsHandlingUserInput) {
nsEventStateManager::StartHandlingUserInput();
if (aIsMouseDown) {
if (mIsMouseDown) {
nsIPresShell::SetCapturingContent(nsnull, 0);
nsIPresShell::AllowMouseCapture(PR_TRUE);
if (aDocument && NS_IS_TRUSTED_EVENT(aEvent)) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetMouseButtonDownHandlingDocument(aDocument);
mResetFMMouseDownState = PR_TRUE;
}
}
}
}
}
@ -454,6 +470,12 @@ public:
nsEventStateManager::StopHandlingUserInput();
if (mIsMouseDown) {
nsIPresShell::AllowMouseCapture(PR_FALSE);
if (mResetFMMouseDownState) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetMouseButtonDownHandlingDocument(nsnull);
}
}
}
}
}
@ -461,6 +483,7 @@ public:
protected:
PRBool mIsHandlingUserInput;
PRBool mIsMouseDown;
PRBool mResetFMMouseDownState;
private:
// Hide so that this class can only be stack-allocated

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

@ -91,6 +91,7 @@ _TEST_FILES = \
test_bug547996-1.html \
test_bug547996-2.xhtml \
test_bug556493.html \
test_bug574663.html \
test_bug586961.xul \
test_clickevent_on_input.html \
test_bug593959.html \

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

@ -0,0 +1,135 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=574663
-->
<head>
<title>Test for Bug 574663</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.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=574663">Mozilla Bug 574663</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/** Test for Bug 574663 **/
// This test depends on general.smoothScroll being off.
function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum) {
var win = scrollbox.ownerDocument.defaultView;
let event = {
'type': "DOMMouseScroll",
'axis': "vertical",
'delta': direction,
'hasPixels': true,
'ctrlKey': ctrl,
'isMomentum': momentum,
};
// first a line scroll
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
// then 5 pixel scrolls
event.delta *= 3;
event.type = "MozMousePixelScroll";
event.hasPixels = false;
for (let i = 0; i < 5; ++i) {
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
}
}
function runTest() {
var win = open('data:text/html,<!DOCTYPE html>\n' +
'<div id="scrollbox" style="height: 100px; overflow: auto;">' +
' <div style="height: 1000px;"></div>' +
'</div>', '_blank', 'width=300,height=300');
SimpleTest.waitForFocus(function () {
var scrollbox = win.document.getElementById("scrollbox");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
let winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
let outstandingTests = [
[false, false],
[false, true],
[true, false],
[true, true],
];
function nextTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (!outstandingTests.length) {
win.close();
clearPrefs();
SimpleTest.finish();
return;
}
let [ctrlKey, isMomentum] = outstandingTests.shift();
let scrollTopBefore = scrollbox.scrollTop;
let zoomFactorBefore = winUtils.screenPixelsPerCSSPixel;
sendTouchpadScrollMotion(scrollbox, 1, ctrlKey, isMomentum);
setTimeout(function () {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (!ctrlKey) {
let postfix = isMomentum ? ", even after releasing the touchpad" : "";
// Normal scroll: scroll
is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
isnot(scrollbox.scrollTop, scrollTopBefore, "Normal scrolling should scroll" + postfix);
} else {
if (!isMomentum) {
isnot(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Ctrl-scrolling should zoom while the user is touching the touchpad");
is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
} else {
is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
isnot(scrollbox.scrollTop, scrollTopBefore, "Momentum scrolling should scroll, even when pressing Ctrl");
}
}
// Revert the effect.
sendTouchpadScrollMotion(scrollbox, -1, ctrlKey, isMomentum);
setTimeout(nextTest, 0);
}, 0);
}
nextTest();
}, win);
}
function initPrefs()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch2);
// Disables the app level scroll acceleration
prefSvc.setIntPref("mousewheel.acceleration.start", -1);
prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
}
function clearPrefs()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch2);
if (prefSvc.prefHasUserValue("mousewheel.acceleration.start"))
prefSvc.clearUserPref("mousewheel.acceleration.start");
if (prefSvc.prefHasUserValue("mousewheel.system_scroll_override_on_root_content.enabled"))
prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
}
window.onload = function () {
initPrefs();
SimpleTest.executeSoon(runTest);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

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

@ -2104,6 +2104,29 @@ nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, PRInt32 aValue)
return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
}
nsresult
nsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aDefault,
PRUint32* aResult)
{
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
*aResult = attrVal->GetIntegerValue();
}
else {
*aResult = aDefault;
}
return NS_OK;
}
nsresult
nsGenericHTMLElement::SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue)
{
nsAutoString value;
value.AppendInt(aValue);
return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
}
nsresult
nsGenericHTMLElement::GetFloatAttr(nsIAtom* aAttr, float aDefault, float* aResult)
{

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

@ -653,6 +653,29 @@ protected:
*/
NS_HIDDEN_(nsresult) SetIntAttr(nsIAtom* aAttr, PRInt32 aValue);
/**
* Helper method for NS_IMPL_UINT_ATTR macro.
* Gets the unsigned integer-value of an attribute, returns specified default
* value if the attribute isn't set or isn't set to an integer. Only works for
* attributes in null namespace.
*
* @param aAttr name of attribute.
* @param aDefault default-value to return if attribute isn't set.
* @param aResult result value [out]
*/
NS_HIDDEN_(nsresult) GetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aDefault,
PRUint32* aValue);
/**
* Helper method for NS_IMPL_UINT_ATTR macro.
* Sets value of attribute to specified unsigned integer. Only works for
* attributes in null namespace.
*
* @param aAttr name of attribute.
* @param aValue Integer value of attribute.
*/
NS_HIDDEN_(nsresult) SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue);
/**
* Helper method for NS_IMPL_FLOAT_ATTR macro.
* Gets the float-value of an attribute, returns specified default value
@ -1129,6 +1152,50 @@ protected:
return SetIntAttr(nsGkAtoms::_atom, aValue); \
}
/**
* A macro to implement the getter and setter for a given unsigned integer
* valued content property. The method uses GetUnsignedIntAttr and
* SetUnsignedIntAttr methods.
*/
#define NS_IMPL_UINT_ATTR(_class, _method, _atom) \
NS_IMPL_UINT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0)
#define NS_IMPL_UINT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \
NS_IMETHODIMP \
_class::Get##_method(PRUint32* aValue) \
{ \
return GetUnsignedIntAttr(nsGkAtoms::_atom, _default, aValue); \
} \
NS_IMETHODIMP \
_class::Set##_method(PRUint32 aValue) \
{ \
return SetUnsignedIntAttr(nsGkAtoms::_atom, aValue); \
}
/**
* A macro to implement the getter and setter for a given unsigned integer
* valued content property. The method uses GetUnsignedIntAttr and
* SetUnsignedIntAttr methods. This macro is similar to NS_IMPL_UINT_ATTR except
* that it throws an exception if the set value is null.
*/
#define NS_IMPL_UINT_ATTR_NON_ZERO(_class, _method, _atom) \
NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(_class, _method, _atom, 1)
#define NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(_class, _method, _atom, _default) \
NS_IMETHODIMP \
_class::Get##_method(PRUint32* aValue) \
{ \
return GetUnsignedIntAttr(nsGkAtoms::_atom, _default, aValue); \
} \
NS_IMETHODIMP \
_class::Set##_method(PRUint32 aValue) \
{ \
if (aValue == 0) { \
return NS_ERROR_DOM_INDEX_SIZE_ERR; \
} \
return SetUnsignedIntAttr(nsGkAtoms::_atom, aValue); \
}
/**
* A macro to implement the getter and setter for a given float
* valued content property. The method uses the generic GetAttr and

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

@ -881,7 +881,9 @@ nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
{
nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(
mSubmitInitiatedFromUserInput,
nsnull, doc);
nsCOMPtr<nsIInputStream> postDataStream;
rv = aFormSubmission->GetEncodedSubmission(actionURI,

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

@ -977,7 +977,7 @@ NS_IMPL_URI_ATTR(nsHTMLInputElement, Src, src)
NS_IMPL_INT_ATTR(nsHTMLInputElement, TabIndex, tabindex)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, UseMap, usemap)
//NS_IMPL_STRING_ATTR(nsHTMLInputElement, Value, value)
//NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Size, size, 0)
NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(nsHTMLInputElement, Size, size, DEFAULT_COLS)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, Pattern, pattern)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, Placeholder, placeholder)
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Type, type,
@ -1019,29 +1019,6 @@ nsHTMLInputElement::SetIndeterminate(PRBool aValue)
return SetIndeterminateInternal(aValue, PR_TRUE);
}
NS_IMETHODIMP
nsHTMLInputElement::GetSize(PRUint32* aValue)
{
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::size);
if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
*aValue = attrVal->GetIntegerValue();
}
else {
*aValue = 0;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLInputElement::SetSize(PRUint32 aValue)
{
nsAutoString val;
val.AppendInt(aValue);
return SetAttr(kNameSpaceID_None, nsGkAtoms::size, val, PR_TRUE);
}
NS_IMETHODIMP
nsHTMLInputElement::GetValue(nsAString& aValue)
{
@ -2691,7 +2668,7 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
return aResult.ParseNonNegativeIntValue(aValue);
}
if (aAttribute == nsGkAtoms::size) {
return aResult.ParseIntWithBounds(aValue, 0);
return aResult.ParsePositiveIntValue(aValue);
}
if (aAttribute == nsGkAtoms::border) {
return aResult.ParseIntWithBounds(aValue, 0);

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

@ -185,6 +185,7 @@ nsHTMLSharedObjectElement::nsHTMLSharedObjectElement(already_AddRefed<nsINodeInf
mIsDoneAddingChildren(mNodeInfo->Equals(nsGkAtoms::embed) || !aFromParser)
{
RegisterFreezableElement();
SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
}
nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement()
@ -455,6 +456,7 @@ nsHTMLSharedObjectElement::StartObjectLoad(PRBool aNotify)
else {
LoadObject(uri, aNotify, type);
}
SetIsNetworkCreated(PR_FALSE);
}
nsEventStates

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

@ -239,6 +239,7 @@ _TEST_FILES = \
test_bug297761.html \
file_bug297761.html \
test_bug607145.html \
test_bug601061.html \
$(NULL)
libs:: $(_TEST_FILES)

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

@ -0,0 +1,118 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=601061
-->
<head>
<title>Test for Bug 601061</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=601061">Mozilla Bug 601061</a>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 601061 **/
function reflectUnsignedInt(aElement, aAttr, aNonNull, aDefault)
{
function checkGetter(aElement, aAttr, aValue)
{
is(aElement[aAttr], aValue, "." + aAttr + " should be equals " + aValue);
is(aElement.getAttribute(aAttr), aValue,
"@" + aAttr + " should be equals " + aValue);
}
if (!aDefault) {
if (aNonNull) {
aDefault = 1;
} else {
aDefault = 0;
}
}
// Check default value.
is(aElement[aAttr], aDefault, "default value should be " + aDefault);
ok(!aElement.hasAttribute(aAttr), aAttr + " shouldn't be present");
var values = [ 1, 3, 42, 2147483647 ];
for each (var value in values) {
aElement[aAttr] = value;
checkGetter(aElement, aAttr, value);
}
for each (var value in values) {
aElement.setAttribute(aAttr, value);
checkGetter(aElement, aAttr, value);
}
// -3000000000 is equivalent to 1294967296 when using the IDL attribute.
aElement[aAttr] = -3000000000;
checkGetter(aElement, aAttr, 1294967296);
// When setting the content atribute, it's a string so it will be unvalid.
aElement.setAttribute(aAttr, -3000000000);
is(aElement.getAttribute(aAttr), -3000000000,
"@" + aAttr + " should be equals to " + -3000000000);
is(aElement[aAttr], aDefault,
"." + aAttr + " should be equals to " + aDefault);
var nonValidValues = [
/* invalid value, value in the unsigned int range */
[ -2147483648, 2147483648 ],
[ -1, 4294967295 ],
[ 3147483647, 3147483647 ],
];
for each (var values in nonValidValues) {
aElement[aAttr] = values[0];
is(aElement.getAttribute(aAttr), values[1],
"@" + aAttr + " should be equals to " + values[1]);
is(aElement[aAttr], aDefault,
"." + aAttr + " should be equals to " + aDefault);
}
for each (var values in nonValidValues) {
aElement.setAttribute(aAttr, values[0]);
is(aElement.getAttribute(aAttr), values[0],
"@" + aAttr + " should be equals to " + values[0]);
is(aElement[aAttr], aDefault,
"." + aAttr + " should be equals to " + aDefault);
}
// Setting to 0 should throw an error if aNonNull is true.
var caught = false;
try {
aElement[aAttr] = 0;
} catch(e) {
caught = true;
is(e.code, DOMException.INDEX_SIZE_ERR, "exception should be INDEX_SIZE_ERR");
}
if (aNonNull) {
ok(caught, "an exception should have been caught");
} else {
ok(!caught, "no exception should have been caught");
}
// If 0 is set in @aAttr, it will be ignored when calling .aAttr.
aElement.setAttribute(aAttr, 0);
is(aElement.getAttribute(aAttr), 0, "@" + aAttr + " should be equals to 0");
if (aNonNull) {
is(aElement[aAttr], aDefault,
"." + aAttr + " should be equals to " + aDefault);
} else {
is(aElement[aAttr], 0, "." + aAttr + " should be equals to 0");
}
}
var input = document.createElement("input");
reflectUnsignedInt(input, "size", true, 20);
</script>
</pre>
</body>
</html>

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

@ -71,7 +71,7 @@ static const double NONSEEKABLE_READAHEAD_MAX = 0.5;
static const PRUint32 REPLAY_DELAY = 30;
// When looking for a reusable block, scan forward this many blocks
// from the desired "best" block location to look for free blocks,
// from the desired "best" block location to look for free blocks,
// before we resort to scanning the whole cache. The idea is to try to
// store runs of stream blocks close-to-consecutively in the cache if we
// can.
@ -556,21 +556,41 @@ nsMediaCache::Init()
nsCOMPtr<nsIFile> tmp;
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmp));
if (NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsILocalFile> tmpFile = do_QueryInterface(tmp);
if (!tmpFile)
return NS_ERROR_FAILURE;
rv = tmpFile->AppendNative(nsDependentCString("moz_media_cache"));
if (NS_FAILED(rv))
return rv;
rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv))
return rv;
NS_ENSURE_TRUE(tmpFile != nsnull, NS_ERROR_FAILURE);
// We put the media cache file in
// ${TempDir}/mozilla-media-cache/media_cache
rv = tmpFile->AppendNative(nsDependentCString("mozilla-media-cache"));
NS_ENSURE_SUCCESS(rv,rv);
rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
// Ensure the permissions are 0700. If not, we won't be able to create,
// read to and write from the media cache file in its subdirectory on
// non-Windows platforms.
PRUint32 perms;
rv = tmpFile->GetPermissions(&perms);
NS_ENSURE_SUCCESS(rv,rv);
if (perms != 0700) {
rv = tmpFile->SetPermissions(0700);
NS_ENSURE_SUCCESS(rv,rv);
}
} else {
NS_ENSURE_SUCCESS(rv,rv);
}
rv = tmpFile->AppendNative(nsDependentCString("media_cache"));
NS_ENSURE_SUCCESS(rv,rv);
rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700);
NS_ENSURE_SUCCESS(rv,rv);
rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsILocalFile::DELETE_ON_CLOSE,
PR_IRWXU, &mFD);
if (NS_FAILED(rv))
return rv;
NS_ENSURE_SUCCESS(rv,rv);
#ifdef PR_LOGGING
if (!gMediaCacheLog) {
@ -616,7 +636,7 @@ nsMediaCache::FlushInternal()
void
nsMediaCache::MaybeShutdown()
{
NS_ASSERTION(NS_IsMainThread(),
NS_ASSERTION(NS_IsMainThread(),
"nsMediaCache::MaybeShutdown called on non-main thread");
if (!gMediaCache->mStreams.IsEmpty()) {
// Don't shut down yet, streams are still alive
@ -1484,7 +1504,7 @@ nsMediaCache::AllocateAndWriteBlock(nsMediaCacheStream* aStream, const void* aDa
if (blockIndex >= 0) {
FreeBlock(blockIndex);
Block* block = &mIndex[blockIndex];
Block* block = &mIndex[blockIndex];
LOG(PR_LOG_DEBUG, ("Allocated block %d to stream %p block %d(%lld)",
blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
@ -1691,7 +1711,7 @@ nsMediaCacheStream::NotifyDataLength(PRInt64 aLength)
}
void
nsMediaCacheStream::NotifyDataStarted(PRInt64 aOffset)
nsMediaCacheStream::NotifyDataStarted(PRInt64 aOffset)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@ -1811,7 +1831,7 @@ nsMediaCacheStream::NotifyDataReceived(PRInt64 aSize, const char* aData,
}
void
nsMediaCacheStream::NotifyDataEnded(nsresult aStatus)
nsMediaCacheStream::NotifyDataEnded(nsresult aStatus)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@ -1975,7 +1995,7 @@ nsMediaCacheStream::GetNextCachedDataInternal(PRInt64 aOffset)
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(gMediaCache->Monitor());
if (aOffset == mStreamLength)
return -1;
PRUint32 startBlockIndex = aOffset/BLOCK_SIZE;
PRUint32 channelBlockIndex = mChannelOffset/BLOCK_SIZE;
@ -2216,7 +2236,7 @@ nsMediaCacheStream::ReadFromCache(char* aBuffer,
streamOffset += bytes;
count += bytes;
}
return NS_OK;
}

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

@ -257,7 +257,7 @@ public:
nsSeekTarget& aResult);
PRBool HasIndex() const {
return mIndex.Count() > 0;
return mIndex.IsInitialized() && mIndex.Count() > 0;
}
// Returns the duration of the active tracks in the media, if we have

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

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
class="reftest-wait">
<script>
function boom()
{
var origSVG = document.documentElement;
var a = document.createElementNS("http://www.w3.org/2000/svg", "animate");
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
var s = document.createElementNS("http://www.w3.org/2000/svg", "svg");
document.removeChild(document.documentElement);
document.appendChild(g);
s.appendChild(a);
g.appendChild(s);
origSVG.removeAttribute("class");
}
window.addEventListener("load", boom, false);
</script>
</svg>

После

Ширина:  |  Высота:  |  Размер: 580 B

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function boom()
{
// NB: <script src> is needed to trigger the bug. I'm being clever by also using it to remove reftest-wait.
var s = "<script src='data:text/javascript,parent.document.documentElement.className=null;'><\/script><svg>";
document.getElementById("f").contentDocument.write(s);
}
</script>
</head>
<body onload="boom();">
<iframe id="f"></iframe>
</body>
</html>

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

@ -22,3 +22,5 @@ load 590425-1.html
load 592477-1.xhtml
load 594653-1.svg
load 596796-1.svg
load 606101-1.svg
load 608295-1.html

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

@ -192,12 +192,14 @@ nsSMILAnimationController::RegisterAnimationElement(
NS_ASSERTION(!mRunningSample, "Registering content during sample.");
mAnimationElementTable.PutEntry(aAnimationElement);
if (mDeferredStartSampling) {
// mAnimationElementTable was empty until we just inserted its first element
NS_ABORT_IF_FALSE(mAnimationElementTable.Count() == 1,
"we shouldn't have deferred sampling if we already had "
"animations registered");
mDeferredStartSampling = PR_FALSE;
StartSampling(GetRefreshDriverForDoc(mDocument));
if (mChildContainerTable.Count()) {
// mAnimationElementTable was empty, but now we've added its 1st element
NS_ABORT_IF_FALSE(mAnimationElementTable.Count() == 1,
"we shouldn't have deferred sampling if we already had "
"animations registered");
StartSampling(GetRefreshDriverForDoc(mDocument));
} // else, don't sample until a time container is registered (via AddChild)
}
}

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

@ -92,18 +92,61 @@ GetZeroValueForUnit(nsStyleAnimation::Unit aUnit)
}
}
static void
InvertSign(nsStyleAnimation::Value& aStyleCoord)
// This method requires at least one of its arguments to be non-null.
//
// If one argument is null, this method updates it to point to "zero"
// for the other argument's Unit (if applicable; otherwise, we return PR_FALSE).
//
// If neither argument is null, this method generally does nothing, though it
// may apply a workaround for the special case where a 0 length-value is mixed
// with a eUnit_Float value. (See comment below.)
//
// Returns PR_TRUE on success, or PR_FALSE.
static const PRBool
FinalizeStyleAnimationValues(const nsStyleAnimation::Value*& aValue1,
const nsStyleAnimation::Value*& aValue2)
{
switch (aStyleCoord.GetUnit()) {
NS_ABORT_IF_FALSE(aValue1 || aValue2,
"expecting at least one non-null value");
// Are we missing either val? (If so, it's an implied 0 in other val's units)
if (!aValue1) {
aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
return !!aValue1; // Fail if we have no zero value for this unit.
}
if (!aValue2) {
aValue2 = GetZeroValueForUnit(aValue1->GetUnit());
return !!aValue2; // Fail if we have no zero value for this unit.
}
// Ok, both values were specified.
// Need to handle a special-case, though: unitless nonzero length (parsed as
// eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord). These
// won't interoperate in nsStyleAnimation, since their Units don't match.
// In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value.
if (*aValue1 == sZeroCoord &&
aValue2->GetUnit() == nsStyleAnimation::eUnit_Float) {
aValue1 = &sZeroFloat;
} else if (*aValue2 == sZeroCoord &&
aValue1->GetUnit() == nsStyleAnimation::eUnit_Float) {
aValue2 = &sZeroFloat;
}
return PR_TRUE;
}
static void
InvertSign(nsStyleAnimation::Value& aValue)
{
switch (aValue.GetUnit()) {
case nsStyleAnimation::eUnit_Coord:
aStyleCoord.SetCoordValue(-aStyleCoord.GetCoordValue());
aValue.SetCoordValue(-aValue.GetCoordValue());
break;
case nsStyleAnimation::eUnit_Percent:
aStyleCoord.SetPercentValue(-aStyleCoord.GetPercentValue());
aValue.SetPercentValue(-aValue.GetPercentValue());
break;
case nsStyleAnimation::eUnit_Float:
aStyleCoord.SetFloatValue(-aStyleCoord.GetFloatValue());
aValue.SetFloatValue(-aValue.GetFloatValue());
break;
default:
NS_NOTREACHED("Calling InvertSign with an unsupported unit");
@ -154,9 +197,6 @@ nsSMILCSSValueType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
if (!destWrapper) {
// barely-initialized dest -- need to alloc & copy
aDest.mU.mPtr = new ValueWrapper(*srcWrapper);
if (!aDest.mU.mPtr) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else {
// both already fully-initialized -- just copy straight across
*destWrapper = *srcWrapper;
@ -221,33 +261,27 @@ nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
return NS_ERROR_FAILURE;
}
// Handle barely-initialized "zero" added value.
const nsStyleAnimation::Value* realValueToAdd = valueToAddWrapper ?
&valueToAddWrapper->mCSSValue :
GetZeroValueForUnit(destWrapper->mCSSValue.GetUnit());
if (!realValueToAdd) {
// No zero value for this unit --> doesn't support addition.
const nsStyleAnimation::Value* valueToAdd = valueToAddWrapper ?
&valueToAddWrapper->mCSSValue : nsnull;
const nsStyleAnimation::Value* destValue = destWrapper ?
&destWrapper->mCSSValue : nsnull;
if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) {
return NS_ERROR_FAILURE;
}
// Did FinalizeStyleAnimationValues change destValue?
// If so, update outparam to use the new value.
if (destWrapper && &destWrapper->mCSSValue != destValue) {
destWrapper->mCSSValue = *destValue;
}
// Handle barely-initialized "zero" destination.
if (!destWrapper) {
// Need to fully initialize destination, since it's an outparam
const nsStyleAnimation::Value* zeroVal =
GetZeroValueForUnit(valueToAddWrapper->mCSSValue.GetUnit());
if (!zeroVal) {
// No zero value for this unit --> doesn't support addition.
return NS_ERROR_FAILURE;
}
aDest.mU.mPtr = destWrapper =
new ValueWrapper(property, *zeroVal, valueToAddWrapper->mPresContext);
if (!destWrapper) {
return NS_ERROR_OUT_OF_MEMORY;
}
new ValueWrapper(property, *destValue, valueToAddWrapper->mPresContext);
}
return nsStyleAnimation::Add(property, destWrapper->mCSSValue,
*realValueToAdd, aCount) ?
return nsStyleAnimation::Add(property,
destWrapper->mCSSValue, *valueToAdd, aCount) ?
NS_OK : NS_ERROR_FAILURE;
}
@ -265,15 +299,15 @@ nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
NS_ABORT_IF_FALSE(toWrapper, "expecting non-null endpoint");
const nsStyleAnimation::Value* fromCSSValue = fromWrapper ?
&fromWrapper->mCSSValue :
GetZeroValueForUnit(toWrapper->mCSSValue.GetUnit());
if (!fromCSSValue) {
// No zero value for this unit --> doesn't support distance-computation.
&fromWrapper->mCSSValue : nsnull;
const nsStyleAnimation::Value* toCSSValue = &toWrapper->mCSSValue;
if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
return NS_ERROR_FAILURE;
}
return nsStyleAnimation::ComputeDistance(toWrapper->mPropID, *fromCSSValue,
toWrapper->mCSSValue, aDistance) ?
return nsStyleAnimation::ComputeDistance(toWrapper->mPropID,
*fromCSSValue, *toCSSValue,
aDistance) ?
NS_OK : NS_ERROR_FAILURE;
}
@ -290,27 +324,26 @@ nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
NS_ABORT_IF_FALSE(aResult.mType == this, "Unexpected result type");
NS_ABORT_IF_FALSE(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
"unit distance value out of bounds");
NS_ABORT_IF_FALSE(!aResult.mU.mPtr, "expecting barely-initialized outparam");
const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal);
const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
NS_ABORT_IF_FALSE(endWrapper, "expecting non-null endpoint");
NS_ABORT_IF_FALSE(!aResult.mU.mPtr, "expecting barely-initialized outparam");
const nsStyleAnimation::Value* startCSSValue = startWrapper ?
&startWrapper->mCSSValue :
GetZeroValueForUnit(endWrapper->mCSSValue.GetUnit());
if (!startCSSValue) {
// No zero value for this unit --> doesn't support interpolation.
&startWrapper->mCSSValue : nsnull;
const nsStyleAnimation::Value* endCSSValue = &endWrapper->mCSSValue;
if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
return NS_ERROR_FAILURE;
}
nsStyleAnimation::Value resultValue;
if (nsStyleAnimation::Interpolate(endWrapper->mPropID, *startCSSValue,
endWrapper->mCSSValue, aUnitDistance,
resultValue)) {
if (nsStyleAnimation::Interpolate(endWrapper->mPropID,
*startCSSValue, *endCSSValue,
aUnitDistance, resultValue)) {
aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue,
endWrapper->mPresContext);
return aResult.mU.mPtr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
@ -389,11 +422,6 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
aString, parsedValue)) {
sSingleton.Init(aValue);
aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
if (!aValue.mU.mPtr) {
// Out of memory! Destroy outparam, to leave it as nsSMILNullType,
// which indicates to our caller that we failed.
sSingleton.Destroy(aValue);
}
}
}

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

@ -62,14 +62,15 @@ public:
* Pause request types.
*/
enum {
PAUSE_BEGIN = 1,
PAUSE_SCRIPT = 2,
PAUSE_PAGEHIDE = 4,
PAUSE_USERPREF = 8
PAUSE_BEGIN = 1, // Paused because timeline has yet to begin.
PAUSE_SCRIPT = 2, // Paused by script.
PAUSE_PAGEHIDE = 4, // Paused because our doc is hidden.
PAUSE_USERPREF = 8, // Paused because animations are disabled in prefs.
PAUSE_IMAGE = 16 // Paused becuase we're in an image that's suspended.
};
/*
* Cause the time container to records its begin time.
* Cause the time container to record its begin time.
*/
void Begin();

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

@ -52,7 +52,26 @@ var _fromByTestLists =
midComp: "rgb(65, 60, 55)",
toComp: "rgb(80, 70, 60)"}),
],
lengthNoUnits: [
new AnimTestcaseFromBy("0", "50", { fromComp: "0px", // 0 acts like 0px
midComp: "25px",
toComp: "50px"}),
new AnimTestcaseFromBy("30", "10", { fromComp: "30px",
midComp: "35px",
toComp: "40px"}),
],
lengthNoUnitsSVG: [
new AnimTestcaseFromBy("0", "50", { fromComp: "0px", // 0 acts like 0px
midComp: "25",
toComp: "50"}),
new AnimTestcaseFromBy("30", "10", { fromComp: "30",
midComp: "35",
toComp: "40"}),
],
lengthPx: [
new AnimTestcaseFromBy("0", "8px", { fromComp: "0px", // 0 acts like 0px
midComp: "4px",
toComp: "8px"}),
new AnimTestcaseFromBy("1px", "10px", { midComp: "6px", toComp: "11px"}),
],
opacity: [
@ -120,7 +139,9 @@ var gFromByBundles =
new AnimTestcaseFromBy("10px serif",
"normal normal 400 100px / 10px monospace"),
]),
new TestcaseBundle(gPropList.font_size, _fromByTestLists.lengthPx),
new TestcaseBundle(gPropList.font_size,
[].concat(_fromByTestLists.lengthNoUnits,
_fromByTestLists.lengthPx)),
new TestcaseBundle(gPropList.font_size_adjust, [
// These testcases implicitly have no effect, because font-size-adjust is
// non-additive (and is declared as such in db_smilCSSPropertyList.js)
@ -149,5 +170,7 @@ var gFromByBundles =
new AnimTestcaseFromBy("10", "5"),
new AnimTestcaseFromBy("1", "2, 3"),
]),
new TestcaseBundle(gPropList.stroke_width, _fromByTestLists.lengthPx),
new TestcaseBundle(gPropList.stroke_width,
[].concat(_fromByTestLists.lengthNoUnitsSVG,
_fromByTestLists.lengthPx))
];

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

@ -105,7 +105,33 @@ var _fromToTestLists = {
"#gradB\") rgb(0, 0, 255)" },
"need support for URI-based paints"),
],
lengthNoUnits: [
new AnimTestcaseFromTo("0", "20", { fromComp: "0px",
midComp: "10px",
toComp: "20px"}),
new AnimTestcaseFromTo("50", "0", { fromComp: "50px",
midComp: "25px",
toComp: "0px"}),
new AnimTestcaseFromTo("30", "80", { fromComp: "30px",
midComp: "55px",
toComp: "80px"}),
],
lengthNoUnitsSVG: [
new AnimTestcaseFromTo("0", "20", { fromComp: "0px", // 0 acts like 0px
midComp: "10",
toComp: "20"}),
new AnimTestcaseFromTo("50", "0", { fromComp: "50",
midComp: "25",
toComp: "0px"}), // 0 acts like 0px
new AnimTestcaseFromTo("30", "80", { fromComp: "30",
midComp: "55",
toComp: "80"}),
],
lengthPx: [
new AnimTestcaseFromTo("0", "12px", { fromComp: "0px", // 0 acts like 0px
midComp: "6px"}),
new AnimTestcaseFromTo("16px", "0", { midComp: "8px",
toComp: "0px"}), // 0 acts like 0px
new AnimTestcaseFromTo("10px", "20px", { midComp: "15px"}),
new AnimTestcaseFromTo("41px", "1px", { midComp: "21px"}),
],
@ -266,7 +292,8 @@ var gFromToBundles = [
new AnimTestcaseFromTo("cursive", "monospace"),
]),
new TestcaseBundle(gPropList.font_size,
[].concat(_fromToTestLists.lengthPx, [
[].concat(_fromToTestLists.lengthNoUnits,
_fromToTestLists.lengthPx, [
new AnimTestcaseFromTo("10px", "40%", { midComp: "15px", toComp: "20px" }),
new AnimTestcaseFromTo("160%", "80%",
{ fromComp: "80px",
@ -331,7 +358,8 @@ var gFromToBundles = [
toComp: "optimizespeed" }),
]),
new TestcaseBundle(gPropList.letter_spacing,
[].concat(_fromToTestLists.lengthPx,
[].concat(_fromToTestLists.lengthNoUnits,
_fromToTestLists.lengthPx,
_fromToTestLists.lengthPxPctSVG)),
new TestcaseBundle(gPropList.letter_spacing,
_fromToTestLists.lengthPctSVG,
@ -388,7 +416,8 @@ var gFromToBundles = [
midComp: "1, 3, 3, 5, 5, 2, 2, 4, 4, 6"}),
])),
new TestcaseBundle(gPropList.stroke_dashoffset,
[].concat(_fromToTestLists.lengthPx,
[].concat(_fromToTestLists.lengthNoUnitsSVG,
_fromToTestLists.lengthPx,
_fromToTestLists.lengthPxPctSVG,
_fromToTestLists.lengthPctSVG)),
new TestcaseBundle(gPropList.stroke_linecap, [
@ -405,7 +434,8 @@ var gFromToBundles = [
]),
new TestcaseBundle(gPropList.stroke_opacity, _fromToTestLists.opacity),
new TestcaseBundle(gPropList.stroke_width,
[].concat(_fromToTestLists.lengthPx,
[].concat(_fromToTestLists.lengthNoUnitsSVG,
_fromToTestLists.lengthPx,
_fromToTestLists.lengthPxPctSVG,
_fromToTestLists.lengthPctSVG, [
new AnimTestcaseFromTo("inherit", "7px",
@ -438,7 +468,8 @@ var gFromToBundles = [
new AnimTestcaseFromTo("hidden", "collapse"),
]),
new TestcaseBundle(gPropList.word_spacing,
[].concat(_fromToTestLists.lengthPx,
[].concat(_fromToTestLists.lengthNoUnits,
_fromToTestLists.lengthPx,
_fromToTestLists.lengthPxPctSVG)),
new TestcaseBundle(gPropList.word_spacing,
_fromToTestLists.lengthPctSVG,

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

@ -92,6 +92,47 @@ var _pacedTestLists =
},
"need support for URI-based paints"),
],
lengthNoUnits : [
new AnimTestcasePaced("2; 0; 4",
{ comp0: "2px",
comp1_6: "1px",
comp1_3: "0px",
comp2_3: "2px",
comp1: "4px"
}),
new AnimTestcasePaced("10; 12; 8",
{ comp0: "10px",
comp1_6: "11px",
comp1_3: "12px",
comp2_3: "10px",
comp1: "8px"
}),
],
lengthNoUnitsSVG : [
new AnimTestcasePaced("2; 0; 4",
{ comp0: "2",
comp1_6: "1",
comp1_3: "0px", // 0 acts like 0px
comp2_3: "2",
comp1: "4"
}),
new AnimTestcasePaced("10; 12; 8",
{ comp0: "10",
comp1_6: "11",
comp1_3: "12",
comp2_3: "10",
comp1: "8"
}),
],
lengthPx : [
new AnimTestcasePaced("0; 2px; 6px",
{ comp0: "0px", // 0 acts like 0px
comp1_6: "1px",
comp1_3: "2px",
comp2_3: "4px",
comp1: "6px"
}),
],
lengthPx : [
new AnimTestcasePaced("0px; 2px; 6px",
{ comp0: "0px",
@ -223,7 +264,8 @@ var gPacedBundles =
[].concat(_pacedTestLists.color,
_pacedTestLists.paintServer)),
new TestcaseBundle(gPropList.font_size,
[].concat(_pacedTestLists.lengthPx, [
[].concat(_pacedTestLists.lengthNoUnits,
_pacedTestLists.lengthPx, [
new AnimTestcasePaced("20%; 24%; 16%",
{ comp0: "10px",
comp1_6: "11px",
@ -280,11 +322,13 @@ var gPacedBundles =
}),
])),
new TestcaseBundle(gPropList.stroke_dashoffset,
[].concat(_pacedTestLists.lengthPx,
[].concat(_pacedTestLists.lengthNoUnitsSVG,
_pacedTestLists.lengthPx,
_pacedTestLists.lengthPctSVG,
_pacedTestLists.lengthPxPctSVG)),
new TestcaseBundle(gPropList.stroke_width,
[].concat(_pacedTestLists.lengthPx,
[].concat(_pacedTestLists.lengthNoUnitsSVG,
_pacedTestLists.lengthPx,
_pacedTestLists.lengthPctSVG,
_pacedTestLists.lengthPxPctSVG)),
// XXXdholbert TODO: test 'stroke-dasharray' once we support animating it

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

@ -273,7 +273,7 @@ DOMSVGLength::NewValueSpecifiedUnits(PRUint16 aUnit, float aValue)
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (HasOwner()) {
InternalItem().SetValueAndUnit(aValue, aUnit);
InternalItem().SetValueAndUnit(aValue, PRUint8(aUnit));
Element()->DidChangeLengthList(mAttrEnum, PR_TRUE);
#ifdef MOZ_SMIL
if (mList->mAList->IsAnimating()) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше