зеркало из https://github.com/mozilla/pjs.git
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:
Коммит
e8e4ffc34f
|
@ -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
|
||||
|
|
44
configure.in
44
configure.in
|
@ -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()) {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче