mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
Merge last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
e520960d8b
@ -746,13 +746,21 @@ nsAccessible::NativeState()
|
||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
|
||||
state |= states::HASPOPUP;
|
||||
|
||||
// Add 'linked' state for simple xlink.
|
||||
if (nsCoreUtils::IsXLink(mContent))
|
||||
state |= states::LINKED;
|
||||
// Bypass the link states specialization for non links.
|
||||
if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
|
||||
mRoleMapEntry->role == roles::LINK)
|
||||
state |= NativeLinkState();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
PRUint64
|
||||
nsAccessible::NativeLinkState() const
|
||||
{
|
||||
// Expose linked state for simple xlink.
|
||||
return nsCoreUtils::IsXLink(mContent) ? states::LINKED : 0;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean focusedChild; */
|
||||
NS_IMETHODIMP
|
||||
nsAccessible::GetFocusedChild(nsIAccessible** aChild)
|
||||
@ -1618,7 +1626,7 @@ nsAccessible::State()
|
||||
}
|
||||
|
||||
void
|
||||
nsAccessible::ApplyARIAState(PRUint64* aState)
|
||||
nsAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
if (!mContent->IsElement())
|
||||
return;
|
||||
|
@ -185,7 +185,7 @@ public:
|
||||
*
|
||||
* @param [in/out] where to fill the states into.
|
||||
*/
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
|
||||
/**
|
||||
* Returns the accessible name provided by native markup. It doesn't take
|
||||
@ -227,12 +227,27 @@ public:
|
||||
*/
|
||||
virtual PRUint64 State();
|
||||
|
||||
/**
|
||||
* Return link states present on the accessible.
|
||||
*/
|
||||
PRUint64 LinkState() const
|
||||
{
|
||||
PRUint64 state = NativeLinkState();
|
||||
ApplyARIAState(&state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the states of accessible, not taking into account ARIA states.
|
||||
* Use State() to get complete set of states.
|
||||
*/
|
||||
virtual PRUint64 NativeState();
|
||||
|
||||
/**
|
||||
* Return native link states present on the accessible.
|
||||
*/
|
||||
virtual PRUint64 NativeLinkState() const;
|
||||
|
||||
/**
|
||||
* Return bit set of invisible and offscreen states.
|
||||
*/
|
||||
|
@ -113,16 +113,12 @@ nsLinkableAccessible::TakeFocus()
|
||||
}
|
||||
|
||||
PRUint64
|
||||
nsLinkableAccessible::NativeState()
|
||||
nsLinkableAccessible::NativeLinkState() const
|
||||
{
|
||||
PRUint64 states = nsAccessibleWrap::NativeState();
|
||||
if (mIsLink) {
|
||||
states |= states::LINKED;
|
||||
if (mActionAcc->State() & states::TRAVERSED)
|
||||
states |= states::TRAVERSED;
|
||||
}
|
||||
if (mIsLink)
|
||||
return states::LINKED | (mActionAcc->LinkState() & states::TRAVERSED);
|
||||
|
||||
return states;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -235,11 +231,10 @@ nsLinkableAccessible::BindToParent(nsAccessible* aParent,
|
||||
// is traversed.
|
||||
nsAccessible* walkUpAcc = this;
|
||||
while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) {
|
||||
if (walkUpAcc->Role() == roles::LINK &&
|
||||
walkUpAcc->State() & states::LINKED) {
|
||||
mIsLink = true;
|
||||
mActionAcc = walkUpAcc;
|
||||
return;
|
||||
if (walkUpAcc->LinkState() & states::LINKED) {
|
||||
mIsLink = true;
|
||||
mActionAcc = walkUpAcc;
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
|
||||
// nsAccessible
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual PRUint64 NativeState();
|
||||
virtual PRUint64 NativeLinkState() const;
|
||||
|
||||
// ActionAccessible
|
||||
virtual PRUint8 ActionCount();
|
||||
|
@ -341,7 +341,7 @@ nsDocAccessible::NativeState()
|
||||
|
||||
// nsAccessible public method
|
||||
void
|
||||
nsDocAccessible::ApplyARIAState(PRUint64* aState)
|
||||
nsDocAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
// Combine with states from outer doc
|
||||
//
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
virtual nsAccessible* FocusedChild();
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
|
||||
virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
|
||||
|
||||
|
@ -1045,7 +1045,7 @@ ARIAGridCellAccessible::IsSelected(bool* aIsSelected)
|
||||
// nsAccessible
|
||||
|
||||
void
|
||||
ARIAGridCellAccessible::ApplyARIAState(PRUint64* aState)
|
||||
ARIAGridCellAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
nsHyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
|
@ -138,7 +138,7 @@ public:
|
||||
NS_DECL_NSIACCESSIBLETABLECELL
|
||||
|
||||
// nsAccessible
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
};
|
||||
|
||||
|
@ -333,7 +333,7 @@ ApplicationAccessible::IsPrimaryForNode() const
|
||||
// nsAccessible public methods
|
||||
|
||||
void
|
||||
ApplicationAccessible::ApplyARIAState(PRUint64* aState)
|
||||
ApplicationAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
virtual void Description(nsString& aDescription);
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
|
@ -437,7 +437,7 @@ HTMLTextFieldAccessible::Value(nsString& aValue)
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState)
|
||||
HTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
nsHyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
|
@ -145,7 +145,7 @@ public:
|
||||
|
||||
// nsAccessible
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
virtual nsresult GetNameInternal(nsAString& aName);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 State();
|
||||
|
@ -231,19 +231,6 @@ nsHTMLAreaAccessible::IsPrimaryForNode() const
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsHTMLAreaAccessible: nsAccessible public
|
||||
|
||||
PRUint64
|
||||
nsHTMLAreaAccessible::NativeState()
|
||||
{
|
||||
// Bypass the link states specialization for non links.
|
||||
if (mRoleMapEntry &&
|
||||
mRoleMapEntry->role != roles::NOTHING &&
|
||||
mRoleMapEntry->role != roles::LINK) {
|
||||
return nsAccessible::NativeState();
|
||||
}
|
||||
|
||||
return nsHTMLLinkAccessible::NativeState();
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsHTMLAreaAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
|
||||
EWhichChildAtPoint aWhichChild)
|
||||
|
@ -102,7 +102,6 @@ public:
|
||||
// nsAccessible
|
||||
virtual void Description(nsString& aDescription);
|
||||
virtual nsresult GetNameInternal(nsAString& aName);
|
||||
virtual PRUint64 NativeState();
|
||||
virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
|
||||
EWhichChildAtPoint aWhichChild);
|
||||
virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
|
||||
|
@ -86,24 +86,23 @@ nsHTMLLinkAccessible::NativeState()
|
||||
states |= states::SELECTABLE;
|
||||
}
|
||||
|
||||
nsEventStates state = mContent->AsElement()->State();
|
||||
if (state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED |
|
||||
NS_EVENT_STATE_UNVISITED)) {
|
||||
states |= states::LINKED;
|
||||
return states;
|
||||
}
|
||||
|
||||
if (state.HasState(NS_EVENT_STATE_VISITED))
|
||||
states |= states::TRAVERSED;
|
||||
PRUint64
|
||||
nsHTMLLinkAccessible::NativeLinkState() const
|
||||
{
|
||||
nsEventStates eventState = mContent->AsElement()->State();
|
||||
if (eventState.HasState(NS_EVENT_STATE_UNVISITED))
|
||||
return states::LINKED;
|
||||
|
||||
return states;
|
||||
}
|
||||
if (eventState.HasState(NS_EVENT_STATE_VISITED))
|
||||
return states::LINKED | states::TRAVERSED;
|
||||
|
||||
// This is a either named anchor (a link with also a name attribute) or
|
||||
// it doesn't have any attributes. Check if 'click' event handler is
|
||||
// registered, otherwise bail out.
|
||||
if (nsCoreUtils::HasClickListener(mContent))
|
||||
states |= states::LINKED;
|
||||
|
||||
return states;
|
||||
return nsCoreUtils::HasClickListener(mContent) ? states::LINKED : 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
virtual PRUint64 NativeLinkState() const;
|
||||
|
||||
// ActionAccessible
|
||||
virtual PRUint8 ActionCount();
|
||||
|
@ -754,12 +754,11 @@ XULTextFieldAccessible::Value(nsString& aValue)
|
||||
}
|
||||
|
||||
void
|
||||
XULTextFieldAccessible::ApplyARIAState(PRUint64* aState)
|
||||
XULTextFieldAccessible::ApplyARIAState(PRUint64* aState) const
|
||||
{
|
||||
nsHyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
||||
|
||||
}
|
||||
|
||||
PRUint64
|
||||
|
@ -265,7 +265,7 @@ public:
|
||||
|
||||
// nsAccessible
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void ApplyARIAState(PRUint64* aState) const;
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
virtual bool CanHaveAnonChildren();
|
||||
|
@ -178,9 +178,9 @@ nsXULLinkAccessible::NativeRole()
|
||||
|
||||
|
||||
PRUint64
|
||||
nsXULLinkAccessible::NativeState()
|
||||
nsXULLinkAccessible::NativeLinkState() const
|
||||
{
|
||||
return nsHyperTextAccessible::NativeState() | states::LINKED;
|
||||
return states::LINKED;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual nsresult GetNameInternal(nsAString& aName);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
virtual PRUint64 NativeLinkState() const;
|
||||
|
||||
// ActionAccessible
|
||||
virtual PRUint8 ActionCount();
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
@ -15,19 +17,53 @@
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
testStates("link1", STATE_LINKED);
|
||||
testStates("link2", STATE_LINKED);
|
||||
testStates("link3", STATE_LINKED);
|
||||
testStates("link4", STATE_LINKED);
|
||||
testStates("link5", 0, 0, STATE_LINKED);
|
||||
// a@href and its text node
|
||||
testStates("link_href", STATE_LINKED);
|
||||
testStates(getAccessible("link_href").firstChild, STATE_LINKED);
|
||||
|
||||
SimpleTest.finish();
|
||||
// a@onclick
|
||||
testStates("link_click", STATE_LINKED);
|
||||
|
||||
// a@onmousedown
|
||||
testStates("link_mousedown", STATE_LINKED);
|
||||
|
||||
// a@onmouseup
|
||||
testStates("link_mouseup", STATE_LINKED);
|
||||
|
||||
// a@role="link"
|
||||
testStates("link_arialink", STATE_LINKED);
|
||||
|
||||
// a@role="button"
|
||||
testStates("link_ariabutton", 0, 0, STATE_LINKED);
|
||||
|
||||
// a (no @href, no click event listener)
|
||||
testStates("link_notlink", 0, 0, STATE_LINKED);
|
||||
|
||||
// a: traversal state
|
||||
testStates("link_traversed", 0, 0, STATE_TRAVERSED);
|
||||
registerA11yEventListener(EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
traversedLinkTester);
|
||||
|
||||
synthesizeMouse(getNode("link_traversed"), 1, 1, { shiftKey: true });
|
||||
}
|
||||
|
||||
var traversedLinkTester = {
|
||||
handleEvent: function traversedLinkTester_handleEvent(aEvent) {
|
||||
unregisterA11yEventListener(EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
traversedLinkTester);
|
||||
aEvent.accessible.rootDocument.window.close();
|
||||
|
||||
testStates("link_traversed", STATE_TRAVERSED);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
@ -41,16 +77,25 @@
|
||||
title="Expose click action if mouseup and mousedown are registered">
|
||||
Mozilla Bug 423409
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=754830"
|
||||
title="Calculate link states separately">
|
||||
Mozilla Bug 754830
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<a id="link1" href="http://mozilla.org">link</a>
|
||||
<a id="link2" onclick="">link</a>
|
||||
<a id="link3" onmousedown="">link</a>
|
||||
<a id="link4" onmouseup="">link</a>
|
||||
<a id="link5">not link</a>
|
||||
<a id="link_href" href="http://mozilla.org">link</a>
|
||||
<a id="link_click" onclick="">link</a>
|
||||
<a id="link_mousedown" onmousedown="">link</a>
|
||||
<a id="link_mouseup" onmouseup="">link</a>
|
||||
<a id="link_arialink" role="link">aria link</a>
|
||||
<a id="link_ariabutton" role="button">aria button</a>
|
||||
<a id="link_notlink">not link</a>
|
||||
|
||||
<a id="link_traversed" href="http://www.example.com" target="_top">example.com</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1364,6 +1364,7 @@ GK_ATOM(unicode_bidi, "unicode-bidi")
|
||||
GK_ATOM(userSpaceOnUse, "userSpaceOnUse")
|
||||
GK_ATOM(view, "view")
|
||||
GK_ATOM(viewBox, "viewBox")
|
||||
GK_ATOM(viewTarget, "viewTarget")
|
||||
GK_ATOM(vkern, "vkern")
|
||||
GK_ATOM(word_spacing, "word-spacing")
|
||||
GK_ATOM(x, "x")
|
||||
|
@ -632,8 +632,8 @@ nsIAtom** const kAttributesSVG[] = {
|
||||
// vert-origin-x
|
||||
// vert-origin-y
|
||||
&nsGkAtoms::viewBox, // viewBox
|
||||
&nsGkAtoms::viewTarget, // viewTarget
|
||||
&nsGkAtoms::visibility, // visibility
|
||||
// viewTarget
|
||||
&nsGkAtoms::width, // width
|
||||
// widths
|
||||
&nsGkAtoms::word_spacing, // word-spacing
|
||||
|
@ -54,6 +54,7 @@ EXPORTS = \
|
||||
nsEventDispatcher.h \
|
||||
nsEventStates.h \
|
||||
nsEventNameList.h \
|
||||
nsVKList.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
|
191
content/events/public/nsVKList.h
Normal file
191
content/events/public/nsVKList.h
Normal file
@ -0,0 +1,191 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This header file defines all DOM keys which are defined in nsIDOMKeyEvent.
|
||||
* You must define NS_DEFINE_VK macro before including this.
|
||||
*
|
||||
* It must have two arguments, (aDOMKeyName, aDOMKeyCode)
|
||||
* aDOMKeyName is a key name in DOM.
|
||||
* aDOMKeyCode is one of nsIDOMKeyEvent::DOM_VK_*.
|
||||
*/
|
||||
|
||||
#define DEFINE_VK_INTERNAL(aKeyName) \
|
||||
NS_DEFINE_VK(VK##aKeyName, nsIDOMKeyEvent::DOM_VK##aKeyName)
|
||||
|
||||
// Some keycode may have different name in nsIDOMKeyEvent from its key name.
|
||||
#define DEFINE_VK_INTERNAL2(aKeyName, aKeyCodeName) \
|
||||
NS_DEFINE_VK(VK##aKeyName, nsIDOMKeyEvent::DOM_VK##aKeyCodeName)
|
||||
|
||||
DEFINE_VK_INTERNAL(_CANCEL),
|
||||
DEFINE_VK_INTERNAL(_HELP),
|
||||
DEFINE_VK_INTERNAL2(_BACK, _BACK_SPACE),
|
||||
DEFINE_VK_INTERNAL(_TAB),
|
||||
DEFINE_VK_INTERNAL(_CLEAR),
|
||||
DEFINE_VK_INTERNAL(_RETURN),
|
||||
DEFINE_VK_INTERNAL(_ENTER),
|
||||
DEFINE_VK_INTERNAL(_SHIFT),
|
||||
DEFINE_VK_INTERNAL(_CONTROL),
|
||||
DEFINE_VK_INTERNAL(_ALT),
|
||||
DEFINE_VK_INTERNAL(_PAUSE),
|
||||
DEFINE_VK_INTERNAL(_CAPS_LOCK),
|
||||
DEFINE_VK_INTERNAL(_KANA),
|
||||
DEFINE_VK_INTERNAL(_HANGUL),
|
||||
DEFINE_VK_INTERNAL(_EISU),
|
||||
DEFINE_VK_INTERNAL(_JUNJA),
|
||||
DEFINE_VK_INTERNAL(_FINAL),
|
||||
DEFINE_VK_INTERNAL(_HANJA),
|
||||
DEFINE_VK_INTERNAL(_KANJI),
|
||||
DEFINE_VK_INTERNAL(_ESCAPE),
|
||||
DEFINE_VK_INTERNAL(_CONVERT),
|
||||
DEFINE_VK_INTERNAL(_NONCONVERT),
|
||||
DEFINE_VK_INTERNAL(_ACCEPT),
|
||||
DEFINE_VK_INTERNAL(_MODECHANGE),
|
||||
DEFINE_VK_INTERNAL(_SPACE),
|
||||
DEFINE_VK_INTERNAL(_PAGE_UP),
|
||||
DEFINE_VK_INTERNAL(_PAGE_DOWN),
|
||||
DEFINE_VK_INTERNAL(_END),
|
||||
DEFINE_VK_INTERNAL(_HOME),
|
||||
DEFINE_VK_INTERNAL(_LEFT),
|
||||
DEFINE_VK_INTERNAL(_UP),
|
||||
DEFINE_VK_INTERNAL(_RIGHT),
|
||||
DEFINE_VK_INTERNAL(_DOWN),
|
||||
DEFINE_VK_INTERNAL(_SELECT),
|
||||
DEFINE_VK_INTERNAL(_PRINT),
|
||||
DEFINE_VK_INTERNAL(_EXECUTE),
|
||||
DEFINE_VK_INTERNAL(_PRINTSCREEN),
|
||||
DEFINE_VK_INTERNAL(_INSERT),
|
||||
DEFINE_VK_INTERNAL(_DELETE),
|
||||
|
||||
DEFINE_VK_INTERNAL(_0),
|
||||
DEFINE_VK_INTERNAL(_1),
|
||||
DEFINE_VK_INTERNAL(_2),
|
||||
DEFINE_VK_INTERNAL(_3),
|
||||
DEFINE_VK_INTERNAL(_4),
|
||||
DEFINE_VK_INTERNAL(_5),
|
||||
DEFINE_VK_INTERNAL(_6),
|
||||
DEFINE_VK_INTERNAL(_7),
|
||||
DEFINE_VK_INTERNAL(_8),
|
||||
DEFINE_VK_INTERNAL(_9),
|
||||
|
||||
DEFINE_VK_INTERNAL(_COLON),
|
||||
DEFINE_VK_INTERNAL(_SEMICOLON),
|
||||
DEFINE_VK_INTERNAL(_LESS_THAN),
|
||||
DEFINE_VK_INTERNAL(_EQUALS),
|
||||
DEFINE_VK_INTERNAL(_GREATER_THAN),
|
||||
DEFINE_VK_INTERNAL(_QUESTION_MARK),
|
||||
DEFINE_VK_INTERNAL(_AT),
|
||||
|
||||
DEFINE_VK_INTERNAL(_A),
|
||||
DEFINE_VK_INTERNAL(_B),
|
||||
DEFINE_VK_INTERNAL(_C),
|
||||
DEFINE_VK_INTERNAL(_D),
|
||||
DEFINE_VK_INTERNAL(_E),
|
||||
DEFINE_VK_INTERNAL(_F),
|
||||
DEFINE_VK_INTERNAL(_G),
|
||||
DEFINE_VK_INTERNAL(_H),
|
||||
DEFINE_VK_INTERNAL(_I),
|
||||
DEFINE_VK_INTERNAL(_J),
|
||||
DEFINE_VK_INTERNAL(_K),
|
||||
DEFINE_VK_INTERNAL(_L),
|
||||
DEFINE_VK_INTERNAL(_M),
|
||||
DEFINE_VK_INTERNAL(_N),
|
||||
DEFINE_VK_INTERNAL(_O),
|
||||
DEFINE_VK_INTERNAL(_P),
|
||||
DEFINE_VK_INTERNAL(_Q),
|
||||
DEFINE_VK_INTERNAL(_R),
|
||||
DEFINE_VK_INTERNAL(_S),
|
||||
DEFINE_VK_INTERNAL(_T),
|
||||
DEFINE_VK_INTERNAL(_U),
|
||||
DEFINE_VK_INTERNAL(_V),
|
||||
DEFINE_VK_INTERNAL(_W),
|
||||
DEFINE_VK_INTERNAL(_X),
|
||||
DEFINE_VK_INTERNAL(_Y),
|
||||
DEFINE_VK_INTERNAL(_Z),
|
||||
|
||||
DEFINE_VK_INTERNAL(_WIN),
|
||||
DEFINE_VK_INTERNAL(_CONTEXT_MENU),
|
||||
DEFINE_VK_INTERNAL(_SLEEP),
|
||||
|
||||
DEFINE_VK_INTERNAL(_NUMPAD0),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD1),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD2),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD3),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD4),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD5),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD6),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD7),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD8),
|
||||
DEFINE_VK_INTERNAL(_NUMPAD9),
|
||||
DEFINE_VK_INTERNAL(_MULTIPLY),
|
||||
DEFINE_VK_INTERNAL(_ADD),
|
||||
DEFINE_VK_INTERNAL(_SEPARATOR),
|
||||
DEFINE_VK_INTERNAL(_SUBTRACT),
|
||||
DEFINE_VK_INTERNAL(_DECIMAL),
|
||||
DEFINE_VK_INTERNAL(_DIVIDE),
|
||||
|
||||
DEFINE_VK_INTERNAL(_F1),
|
||||
DEFINE_VK_INTERNAL(_F2),
|
||||
DEFINE_VK_INTERNAL(_F3),
|
||||
DEFINE_VK_INTERNAL(_F4),
|
||||
DEFINE_VK_INTERNAL(_F5),
|
||||
DEFINE_VK_INTERNAL(_F6),
|
||||
DEFINE_VK_INTERNAL(_F7),
|
||||
DEFINE_VK_INTERNAL(_F8),
|
||||
DEFINE_VK_INTERNAL(_F9),
|
||||
DEFINE_VK_INTERNAL(_F10),
|
||||
DEFINE_VK_INTERNAL(_F11),
|
||||
DEFINE_VK_INTERNAL(_F12),
|
||||
DEFINE_VK_INTERNAL(_F13),
|
||||
DEFINE_VK_INTERNAL(_F14),
|
||||
DEFINE_VK_INTERNAL(_F15),
|
||||
DEFINE_VK_INTERNAL(_F16),
|
||||
DEFINE_VK_INTERNAL(_F17),
|
||||
DEFINE_VK_INTERNAL(_F18),
|
||||
DEFINE_VK_INTERNAL(_F19),
|
||||
DEFINE_VK_INTERNAL(_F20),
|
||||
DEFINE_VK_INTERNAL(_F21),
|
||||
DEFINE_VK_INTERNAL(_F22),
|
||||
DEFINE_VK_INTERNAL(_F23),
|
||||
DEFINE_VK_INTERNAL(_F24),
|
||||
|
||||
DEFINE_VK_INTERNAL(_NUM_LOCK),
|
||||
DEFINE_VK_INTERNAL(_SCROLL_LOCK),
|
||||
|
||||
DEFINE_VK_INTERNAL(_CIRCUMFLEX),
|
||||
DEFINE_VK_INTERNAL(_EXCLAMATION),
|
||||
DEFINE_VK_INTERNAL(_DOUBLE_QUOTE),
|
||||
DEFINE_VK_INTERNAL(_HASH),
|
||||
DEFINE_VK_INTERNAL(_DOLLAR),
|
||||
DEFINE_VK_INTERNAL(_PERCENT),
|
||||
DEFINE_VK_INTERNAL(_AMPERSAND),
|
||||
DEFINE_VK_INTERNAL(_UNDERSCORE),
|
||||
DEFINE_VK_INTERNAL(_OPEN_PAREN),
|
||||
DEFINE_VK_INTERNAL(_CLOSE_PAREN),
|
||||
DEFINE_VK_INTERNAL(_ASTERISK),
|
||||
DEFINE_VK_INTERNAL(_PLUS),
|
||||
DEFINE_VK_INTERNAL(_PIPE),
|
||||
DEFINE_VK_INTERNAL(_HYPHEN_MINUS),
|
||||
|
||||
DEFINE_VK_INTERNAL(_OPEN_CURLY_BRACKET),
|
||||
DEFINE_VK_INTERNAL(_CLOSE_CURLY_BRACKET),
|
||||
|
||||
DEFINE_VK_INTERNAL(_TILDE),
|
||||
|
||||
DEFINE_VK_INTERNAL(_COMMA),
|
||||
DEFINE_VK_INTERNAL(_PERIOD),
|
||||
DEFINE_VK_INTERNAL(_SLASH),
|
||||
DEFINE_VK_INTERNAL(_BACK_QUOTE),
|
||||
DEFINE_VK_INTERNAL(_OPEN_BRACKET),
|
||||
DEFINE_VK_INTERNAL(_BACK_SLASH),
|
||||
DEFINE_VK_INTERNAL(_CLOSE_BRACKET),
|
||||
DEFINE_VK_INTERNAL(_QUOTE),
|
||||
|
||||
DEFINE_VK_INTERNAL(_META),
|
||||
DEFINE_VK_INTERNAL(_ALTGR)
|
||||
|
||||
#undef DEFINE_VK_INTERNAL
|
||||
#undef DEFINE_VK_INTERNAL2
|
@ -354,6 +354,23 @@ nsSMILTimedElement::GetStartTime() const
|
||||
: nsSMILTimeValue();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Hyperlinking support
|
||||
|
||||
nsSMILTimeValue
|
||||
nsSMILTimedElement::GetHyperlinkTime() const
|
||||
{
|
||||
nsSMILTimeValue hyperlinkTime; // Default ctor creates unresolved time
|
||||
|
||||
if (mElementState == STATE_ACTIVE) {
|
||||
hyperlinkTime = mCurrentInterval->Begin()->Time();
|
||||
} else if (!mBeginInstances.IsEmpty()) {
|
||||
hyperlinkTime = mBeginInstances[0]->Time();
|
||||
}
|
||||
|
||||
return hyperlinkTime;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSMILTimedElement
|
||||
|
||||
@ -1492,7 +1509,8 @@ nsSMILTimedElement::FilterIntervals()
|
||||
// We can filter old intervals that:
|
||||
//
|
||||
// a) are not the previous interval; AND
|
||||
// b) are not in the middle of a dependency chain
|
||||
// b) are not in the middle of a dependency chain; AND
|
||||
// c) are not the first interval
|
||||
//
|
||||
// Condition (a) is necessary since the previous interval is used for applying
|
||||
// fill effects and updating the current interval.
|
||||
@ -1502,6 +1520,15 @@ nsSMILTimedElement::FilterIntervals()
|
||||
// intervals. Such chains are used to establish priorities within the
|
||||
// animation sandwich.
|
||||
//
|
||||
// Condition (c) is necessary to support hyperlinks that target animations
|
||||
// since in some cases the defined behavior is to seek the document back to
|
||||
// the first resolved begin time. Presumably the intention here is not
|
||||
// actually to use the first resolved begin time, the
|
||||
// _the_first_resolved_begin_time_that_produced_an_interval. That is,
|
||||
// if we have begin="-5s; -3s; 1s; 3s" with a duration on 1s, we should seek
|
||||
// to 1s. The spec doesn't say this but I'm pretty sure that is the intention.
|
||||
// It seems negative times were simply not considered.
|
||||
//
|
||||
// Although the above conditions allow us to safely filter intervals for most
|
||||
// scenarios they do not cover all cases and there will still be scenarios
|
||||
// that generate intervals indefinitely. In such a case we simply set
|
||||
@ -1514,7 +1541,8 @@ nsSMILTimedElement::FilterIntervals()
|
||||
for (PRUint32 i = 0; i < mOldIntervals.Length(); ++i)
|
||||
{
|
||||
nsSMILInterval* interval = mOldIntervals[i].get();
|
||||
if (i + 1 < mOldIntervals.Length() /*skip previous interval*/ &&
|
||||
if (i != 0 && /*skip first interval*/
|
||||
i + 1 < mOldIntervals.Length() && /*skip previous interval*/
|
||||
(i < threshold || !interval->IsDependencyChainLink())) {
|
||||
interval->Unlink(true /*filtered, not deleted*/);
|
||||
} else {
|
||||
@ -1584,6 +1612,7 @@ nsSMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList)
|
||||
// There are a few instance times we should keep though, notably:
|
||||
// - the current interval begin time,
|
||||
// - the previous interval end time (see note in RemoveInstanceTimes)
|
||||
// - the first interval begin time (see note in FilterIntervals)
|
||||
nsTArray<const nsSMILInstanceTime *> timesToKeep;
|
||||
if (mCurrentInterval) {
|
||||
timesToKeep.AppendElement(mCurrentInterval->Begin());
|
||||
@ -1592,6 +1621,9 @@ nsSMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList)
|
||||
if (prevInterval) {
|
||||
timesToKeep.AppendElement(prevInterval->End());
|
||||
}
|
||||
if (!mOldIntervals.IsEmpty()) {
|
||||
timesToKeep.AppendElement(mOldIntervals[0]->Begin());
|
||||
}
|
||||
RemoveBelowThreshold removeBelowThreshold(threshold, timesToKeep);
|
||||
RemoveInstanceTimes(aList, removeBelowThreshold);
|
||||
}
|
||||
|
@ -139,10 +139,29 @@ public:
|
||||
return mSimpleDur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods for supporting hyperlinking
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal SMIL methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the time to seek the document to when this element is targetted by
|
||||
* a hyperlink.
|
||||
*
|
||||
* The behavior is defined here:
|
||||
* http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
|
||||
*
|
||||
* It is very similar to GetStartTime() with the exception that when the
|
||||
* element is not active, the begin time of the *first* interval is returned.
|
||||
*
|
||||
* @return the time to seek the documen to in milliseconds or an unresolved
|
||||
* time if there is no resolved interval.
|
||||
*/
|
||||
nsSMILTimeValue GetHyperlinkTime() const;
|
||||
|
||||
/**
|
||||
* Adds an instance time object this element's list of instance times.
|
||||
* These instance times are used when creating intervals.
|
||||
|
@ -78,6 +78,7 @@ _TEST_FILES = \
|
||||
test_smilFillMode.xhtml \
|
||||
test_smilGetStartTime.xhtml \
|
||||
test_smilGetSimpleDuration.xhtml \
|
||||
test_smilHyperlinking.xhtml \
|
||||
test_smilKeySplines.xhtml \
|
||||
test_smilKeyTimes.xhtml \
|
||||
test_smilKeyTimesPacedMode.xhtml \
|
||||
|
233
content/smil/test/test_smilHyperlinking.xhtml
Normal file
233
content/smil/test/test_smilHyperlinking.xhtml
Normal file
@ -0,0 +1,233 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for hyperlinking</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
|
||||
onload="this.pauseAnimations()">
|
||||
<circle cx="-100" cy="20" r="15" fill="blue" id="circle"/>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for SMIL keySplines **/
|
||||
|
||||
/* Global Variables */
|
||||
const SVGNS="http://www.w3.org/2000/svg";
|
||||
var gSvg = document.getElementById("svg");
|
||||
var gAnim;
|
||||
|
||||
var gTestStages =
|
||||
[ testActive,
|
||||
testSeekToFirst,
|
||||
testKickStart,
|
||||
testKickStartWithUnresolved,
|
||||
testFiltering
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function continueTest()
|
||||
{
|
||||
if (gTestStages.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.hash = "";
|
||||
if (gAnim) {
|
||||
gAnim.parentNode.removeChild(gAnim);
|
||||
}
|
||||
gAnim = createAnim();
|
||||
gSvg.setCurrentTime(0);
|
||||
gTestStages.shift()();
|
||||
}
|
||||
|
||||
function createAnim() {
|
||||
var anim = document.createElementNS(SVGNS,'animate');
|
||||
anim.setAttribute('attributeName','cx');
|
||||
anim.setAttribute('from','0');
|
||||
anim.setAttribute('to','100');
|
||||
anim.setAttribute('dur','1s');
|
||||
anim.setAttribute('begin','indefinite');
|
||||
anim.setAttribute('id','anim');
|
||||
return document.getElementById('circle').appendChild(anim);
|
||||
}
|
||||
|
||||
// Traversing a hyperlink, condition 1:
|
||||
//
|
||||
// "If the target element is active, seek the document time back to the
|
||||
// (current) begin time of the element. If there are multiple begin times, use
|
||||
// the begin time that corresponds to the current "begin instance"."
|
||||
//
|
||||
function testActive() {
|
||||
gAnim.setAttribute('begin','2s; 4s');
|
||||
gSvg.setCurrentTime(2.5);
|
||||
fireLink(rewindActiveInterval1);
|
||||
}
|
||||
|
||||
function rewindActiveInterval1() {
|
||||
is(gSvg.getCurrentTime(), 2,
|
||||
"Unexpected time after activating link to animation in the middle of " +
|
||||
"first active interval");
|
||||
|
||||
// Seek to second interval
|
||||
gSvg.setCurrentTime(4.5);
|
||||
fireLink(rewindActiveInterval2);
|
||||
}
|
||||
|
||||
function rewindActiveInterval2() {
|
||||
is(gSvg.getCurrentTime(), 4,
|
||||
"Unexpected time after activating link to animation in the middle of " +
|
||||
"second active interval");
|
||||
|
||||
// Try a negative time
|
||||
gAnim.setAttribute("begin", "-0.5");
|
||||
gSvg.setCurrentTime(0.2);
|
||||
fireLink(rewindActiveIntervalAtZero);
|
||||
}
|
||||
|
||||
function rewindActiveIntervalAtZero() {
|
||||
is(gSvg.getCurrentTime(), 0,
|
||||
"Unexpected time after activating link to animation in the middle of " +
|
||||
"an active interval that overlaps zero");
|
||||
|
||||
continueTest();
|
||||
}
|
||||
|
||||
// Traversing a hyperlink, condition 2:
|
||||
//
|
||||
// "Else if the target element begin time is resolved (i.e., there is any
|
||||
// resolved time in the list of begin times, or if the begin time was forced by
|
||||
// an earlier hyperlink or a beginElement() method call), seek the document time
|
||||
// (forward or back, as needed) to the earliest resolved begin time of the
|
||||
// target element. Note that the begin time may be resolved as a result of an
|
||||
// earlier hyperlink, DOM or event activation. Once the begin time is resolved,
|
||||
// hyperlink traversal always seeks."
|
||||
//
|
||||
function testSeekToFirst() {
|
||||
// Seek forwards
|
||||
gAnim.setAttribute('begin','2s');
|
||||
gSvg.setCurrentTime(0);
|
||||
fireLink(forwardToInterval1);
|
||||
}
|
||||
|
||||
function forwardToInterval1() {
|
||||
is(gSvg.getCurrentTime(), 2,
|
||||
"Unexpected time after activating link to animation scheduled to start " +
|
||||
"the future");
|
||||
|
||||
// Seek backwards
|
||||
gSvg.setCurrentTime(3.5);
|
||||
fireLink(backwardToInterval1);
|
||||
}
|
||||
|
||||
function backwardToInterval1() {
|
||||
is(gSvg.getCurrentTime(), 2,
|
||||
"Unexpected time after activating link to animation that ran in the past");
|
||||
|
||||
// What if the first begin instance is negative?
|
||||
gAnim.setAttribute('begin','-0.5s');
|
||||
gSvg.setCurrentTime(1);
|
||||
fireLink(backwardToZero);
|
||||
}
|
||||
|
||||
function backwardToZero() {
|
||||
is(gSvg.getCurrentTime(), 0,
|
||||
"Unexpected time after activating link to animation that ran in the " +
|
||||
"past with a negative time");
|
||||
|
||||
continueTest();
|
||||
}
|
||||
|
||||
// Traversing a hyperlink, condition 3:
|
||||
//
|
||||
// "Else (animation begin time is unresolved) just resolve the target animation
|
||||
// begin time at current document time. Disregard the sync-base or event base of
|
||||
// the animation, and do not "back-propagate" any timing logic to resolve the
|
||||
// child, but rather treat it as though it were defined with begin="indefinite"
|
||||
// and just resolve begin time to the current document time."
|
||||
//
|
||||
function testKickStart() {
|
||||
gSvg.setCurrentTime(1);
|
||||
fireLink(startedAt1s);
|
||||
}
|
||||
|
||||
function startedAt1s() {
|
||||
is(gSvg.getCurrentTime(), 1,
|
||||
"Unexpected time after kick-starting animation with indefinite start " +
|
||||
"by hyperlink");
|
||||
is(gAnim.getStartTime(), 1,
|
||||
"Unexpected start time for kick-started animation");
|
||||
|
||||
continueTest();
|
||||
}
|
||||
|
||||
function testKickStartWithUnresolved() {
|
||||
gAnim.setAttribute("begin", "circle.click");
|
||||
gSvg.setCurrentTime(3);
|
||||
fireLink(startedAt3s);
|
||||
}
|
||||
|
||||
function startedAt3s() {
|
||||
is(gSvg.getCurrentTime(), 3,
|
||||
"Unexpected time after kick-starting animation with unresolved start " +
|
||||
"by hyperlink");
|
||||
is(gAnim.getStartTime(), 3,
|
||||
"Unexpected start time for kick-started animation with unresolved begin " +
|
||||
"condition");
|
||||
|
||||
continueTest();
|
||||
}
|
||||
|
||||
function testFiltering() {
|
||||
gAnim.setAttribute('begin','-3s; 1s; 2s; 3s; 4s; 5s; 6s; 7s; 8s; 9s; 10s');
|
||||
gSvg.setCurrentTime(12);
|
||||
fireLink(rewindToFirst);
|
||||
}
|
||||
|
||||
function rewindToFirst() {
|
||||
is(gSvg.getCurrentTime(), 1,
|
||||
"Unexpected time after triggering animation with a hyperlink after " +
|
||||
"numerous intervals have passed");
|
||||
|
||||
continueTest();
|
||||
}
|
||||
|
||||
function fireLink(callback) {
|
||||
// First we need to reset the hash because otherwise the redundant hashchange
|
||||
// events will be suppressed
|
||||
if (window.location.hash === '') {
|
||||
fireLinkPart2(callback);
|
||||
} else {
|
||||
window.location.hash = '';
|
||||
window.addEventListener("hashchange",
|
||||
function clearHash() {
|
||||
window.removeEventListener("hashchange", clearHash, false);
|
||||
window.setTimeout(fireLinkPart2, 0, callback);
|
||||
},
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
function fireLinkPart2(callback) {
|
||||
window.addEventListener("hashchange",
|
||||
function triggerCallback() {
|
||||
window.removeEventListener("hashchange", triggerCallback, false);
|
||||
window.setTimeout(callback, 0);
|
||||
},
|
||||
false);
|
||||
window.location.hash = '#anim';
|
||||
}
|
||||
|
||||
window.addEventListener("load", continueTest, false);
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -124,12 +124,14 @@ CPPSRCS = \
|
||||
nsSVGUnknownElement.cpp \
|
||||
nsSVGUseElement.cpp \
|
||||
nsSVGViewBox.cpp \
|
||||
nsSVGViewElement.cpp \
|
||||
SVGAnimatedLengthList.cpp \
|
||||
SVGAnimatedNumberList.cpp \
|
||||
SVGAnimatedPathSegList.cpp \
|
||||
SVGAnimatedPointList.cpp \
|
||||
SVGAnimatedPreserveAspectRatio.cpp \
|
||||
SVGAnimatedTransformList.cpp \
|
||||
SVGFragmentIdentifier.cpp \
|
||||
SVGLength.cpp \
|
||||
SVGLengthList.cpp \
|
||||
SVGNumberList.cpp \
|
||||
|
@ -149,6 +149,14 @@ GetMeetOrSliceString(nsAString& aMeetOrSliceString, PRUint16 aMeetOrSlice)
|
||||
nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET]);
|
||||
}
|
||||
|
||||
bool
|
||||
SVGPreserveAspectRatio::operator==(const SVGPreserveAspectRatio& aOther) const
|
||||
{
|
||||
return mAlign == aOther.mAlign &&
|
||||
mMeetOrSlice == aOther.mMeetOrSlice &&
|
||||
mDefer == aOther.mDefer;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedPreserveAspectRatio::ToDOMBaseVal(
|
||||
nsIDOMSVGPreserveAspectRatio **aResult,
|
||||
@ -273,48 +281,25 @@ SVGAnimatedPreserveAspectRatio::GetBaseValueString(
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedPreserveAspectRatio::SetBaseAlign(PRUint16 aAlign,
|
||||
void
|
||||
SVGAnimatedPreserveAspectRatio::SetBaseValue(const SVGPreserveAspectRatio &aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal.GetAlign() == aAlign) {
|
||||
return NS_OK;
|
||||
if (mIsBaseSet && mBaseVal == aValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
|
||||
nsresult rv = mBaseVal.SetAlign(aAlign);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mBaseVal = aValue;
|
||||
mIsBaseSet = true;
|
||||
|
||||
mAnimVal.mAlign = mBaseVal.mAlign;
|
||||
if (!mIsAnimated) {
|
||||
mAnimVal = mBaseVal;
|
||||
}
|
||||
aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedPreserveAspectRatio::SetBaseMeetOrSlice(PRUint16 aMeetOrSlice,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mIsBaseSet && mBaseVal.GetMeetOrSlice() == aMeetOrSlice) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
|
||||
nsresult rv = mBaseVal.SetMeetOrSlice(aMeetOrSlice);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mIsBaseSet = true;
|
||||
|
||||
mAnimVal.mMeetOrSlice = mBaseVal.mMeetOrSlice;
|
||||
aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,12 +60,20 @@ class SVGPreserveAspectRatio
|
||||
friend class SVGAnimatedPreserveAspectRatio;
|
||||
|
||||
public:
|
||||
SVGPreserveAspectRatio(PRUint16 aAlign, PRUint16 aMeetOrSlice, bool aDefer = false)
|
||||
: mAlign(aAlign)
|
||||
, mMeetOrSlice(aMeetOrSlice)
|
||||
, mDefer(aDefer)
|
||||
{};
|
||||
|
||||
SVGPreserveAspectRatio()
|
||||
: mAlign(0)
|
||||
, mMeetOrSlice(0)
|
||||
, mDefer(false)
|
||||
{};
|
||||
|
||||
bool operator==(const SVGPreserveAspectRatio& aOther) const;
|
||||
|
||||
nsresult SetAlign(PRUint16 aAlign) {
|
||||
if (aAlign < nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE ||
|
||||
aAlign > nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX)
|
||||
@ -120,8 +128,28 @@ public:
|
||||
nsSVGElement *aSVGElement);
|
||||
void GetBaseValueString(nsAString& aValue) const;
|
||||
|
||||
nsresult SetBaseAlign(PRUint16 aAlign, nsSVGElement *aSVGElement);
|
||||
nsresult SetBaseMeetOrSlice(PRUint16 aMeetOrSlice, nsSVGElement *aSVGElement);
|
||||
void SetBaseValue(const SVGPreserveAspectRatio &aValue,
|
||||
nsSVGElement *aSVGElement);
|
||||
nsresult SetBaseAlign(PRUint16 aAlign, nsSVGElement *aSVGElement) {
|
||||
if (aAlign < nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE ||
|
||||
aAlign > nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SetBaseValue(SVGPreserveAspectRatio(
|
||||
aAlign, mBaseVal.GetMeetOrSlice(), mBaseVal.GetDefer()),
|
||||
aSVGElement);
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult SetBaseMeetOrSlice(PRUint16 aMeetOrSlice, nsSVGElement *aSVGElement) {
|
||||
if (aMeetOrSlice < nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET ||
|
||||
aMeetOrSlice > nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SetBaseValue(SVGPreserveAspectRatio(
|
||||
mBaseVal.GetAlign(), aMeetOrSlice, mBaseVal.GetDefer()),
|
||||
aSVGElement);
|
||||
return NS_OK;
|
||||
}
|
||||
void SetAnimValue(PRUint64 aPackedValue, nsSVGElement *aSVGElement);
|
||||
|
||||
const SVGPreserveAspectRatio &GetBaseValue() const
|
||||
|
260
content/svg/content/src/SVGFragmentIdentifier.cpp
Normal file
260
content/svg/content/src/SVGFragmentIdentifier.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Robert Longson <longsonr@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "SVGFragmentIdentifier.h"
|
||||
#include "CharTokenizer.h"
|
||||
#include "nsIDOMSVGDocument.h"
|
||||
#include "nsSVGSVGElement.h"
|
||||
#include "nsSVGViewElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static nsSVGEnumMapping sZoomAndPanMap[] = {
|
||||
{&nsGkAtoms::disable, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_DISABLE},
|
||||
{&nsGkAtoms::magnify, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY},
|
||||
{nsnull, 0}
|
||||
};
|
||||
|
||||
static bool
|
||||
IsMatchingParameter(const nsAString &aString, const nsAString &aParameterName)
|
||||
{
|
||||
return StringBeginsWith(aString, aParameterName) &&
|
||||
aString.CharAt(aParameterName.Length()) == '(' &&
|
||||
aString.Last() == ')';
|
||||
}
|
||||
|
||||
static nsSVGViewElement*
|
||||
GetViewElement(nsIDocument *aDocument, const nsAString &aId)
|
||||
{
|
||||
dom::Element* element = aDocument->GetElementById(aId);
|
||||
return (element && element->IsSVG(nsGkAtoms::view)) ?
|
||||
static_cast<nsSVGViewElement*>(element) : nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::SaveOldPreserveAspectRatio(nsSVGSVGElement *root)
|
||||
{
|
||||
const SVGPreserveAspectRatio *oldPARPtr = root->GetPreserveAspectRatioProperty();
|
||||
if (!oldPARPtr) {
|
||||
root->SetPreserveAspectRatioProperty(root->mPreserveAspectRatio.GetBaseValue());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(nsSVGSVGElement *root)
|
||||
{
|
||||
const SVGPreserveAspectRatio *oldPARPtr = root->GetPreserveAspectRatioProperty();
|
||||
if (oldPARPtr) {
|
||||
root->mPreserveAspectRatio.SetBaseValue(*oldPARPtr, root);
|
||||
root->ClearPreserveAspectRatioProperty();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::SaveOldViewBox(nsSVGSVGElement *root)
|
||||
{
|
||||
const nsSVGViewBoxRect *oldViewBoxPtr = root->GetViewBoxProperty();
|
||||
if (!oldViewBoxPtr) {
|
||||
root->SetViewBoxProperty(root->mViewBox.GetBaseValue());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::RestoreOldViewBox(nsSVGSVGElement *root)
|
||||
{
|
||||
const nsSVGViewBoxRect *oldViewBoxPtr = root->GetViewBoxProperty();
|
||||
if (oldViewBoxPtr) {
|
||||
root->mViewBox.SetBaseValue(*oldViewBoxPtr, root);
|
||||
root->ClearViewBoxProperty();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::SaveOldZoomAndPan(nsSVGSVGElement *root)
|
||||
{
|
||||
const PRUint16 *oldZoomAndPanPtr = root->GetZoomAndPanProperty();
|
||||
if (!oldZoomAndPanPtr) {
|
||||
root->SetZoomAndPanProperty(root->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].GetBaseValue());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SVGFragmentIdentifier::RestoreOldZoomAndPan(nsSVGSVGElement *root)
|
||||
{
|
||||
const PRUint16 *oldZoomAndPanPtr = root->GetZoomAndPanProperty();
|
||||
if (oldZoomAndPanPtr) {
|
||||
root->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].SetBaseValue(*oldZoomAndPanPtr, root);
|
||||
root->ClearZoomAndPanProperty();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString &aViewSpec,
|
||||
nsSVGSVGElement *root)
|
||||
{
|
||||
if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SVGViewAttribute may occur in any order, but each type may only occur at most one time
|
||||
// in a correctly formed SVGViewSpec.
|
||||
// If we encounter any element more than once or get any syntax errors we're going to
|
||||
// return without updating the root element
|
||||
|
||||
const nsAString *viewBoxParams = nsnull;
|
||||
const nsAString *preserveAspectRatioParams = nsnull;
|
||||
const nsAString *zoomAndPanParams = nsnull;
|
||||
|
||||
// Each token is a SVGViewAttribute
|
||||
PRInt32 bracketPos = aViewSpec.FindChar('(');
|
||||
CharTokenizer<';'>tokenizer(
|
||||
Substring(aViewSpec, bracketPos + 1, aViewSpec.Length() - bracketPos - 2));
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
|
||||
nsAutoString token(tokenizer.nextToken());
|
||||
|
||||
bracketPos = token.FindChar('(');
|
||||
if (bracketPos < 1 || token.Last() != ')') {
|
||||
// invalid SVGViewAttribute syntax
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsAString ¶ms =
|
||||
Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
|
||||
|
||||
if (IsMatchingParameter(token, NS_LITERAL_STRING("viewBox"))) {
|
||||
if (viewBoxParams) {
|
||||
return false;
|
||||
}
|
||||
viewBoxParams = ¶ms;
|
||||
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
|
||||
if (preserveAspectRatioParams) {
|
||||
return false;
|
||||
}
|
||||
preserveAspectRatioParams = ¶ms;
|
||||
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
|
||||
if (zoomAndPanParams) {
|
||||
return false;
|
||||
}
|
||||
zoomAndPanParams = ¶ms;
|
||||
} else {
|
||||
// We don't support transform or viewTarget currently
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const nsSVGViewBoxRect *oldViewBoxPtr = root->GetViewBoxProperty();
|
||||
if (viewBoxParams) {
|
||||
SaveOldViewBox(root);
|
||||
root->mViewBox.SetBaseValueString(*viewBoxParams, root);
|
||||
} else {
|
||||
RestoreOldViewBox(root);
|
||||
}
|
||||
|
||||
const SVGPreserveAspectRatio *oldPARPtr = root->GetPreserveAspectRatioProperty();
|
||||
if (preserveAspectRatioParams) {
|
||||
SaveOldPreserveAspectRatio(root);
|
||||
root->mPreserveAspectRatio.SetBaseValueString(*preserveAspectRatioParams, root);
|
||||
} else {
|
||||
RestoreOldPreserveAspectRatio(root);
|
||||
}
|
||||
|
||||
const PRUint16 *oldZoomAndPanPtr = root->GetZoomAndPanProperty();
|
||||
if (zoomAndPanParams) {
|
||||
SaveOldZoomAndPan(root);
|
||||
nsCOMPtr<nsIAtom> valAtom = do_GetAtom(*zoomAndPanParams);
|
||||
const nsSVGEnumMapping *mapping = root->sZoomAndPanMap;
|
||||
while (mapping->mKey) {
|
||||
if (valAtom == *(mapping->mKey)) {
|
||||
root->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].SetBaseValue(mapping->mVal, root);
|
||||
break;
|
||||
}
|
||||
mapping++;
|
||||
}
|
||||
} else {
|
||||
RestoreOldZoomAndPan(root);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument *aDocument,
|
||||
const nsAString &aAnchorName)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aDocument->GetRootElement()->IsSVG(nsGkAtoms::svg),
|
||||
"expecting an SVG root element");
|
||||
|
||||
nsSVGSVGElement *rootElement =
|
||||
static_cast<nsSVGSVGElement*>(aDocument->GetRootElement());
|
||||
|
||||
const nsSVGViewElement *viewElement = GetViewElement(aDocument, aAnchorName);
|
||||
|
||||
if (viewElement) {
|
||||
if (viewElement->mViewBox.IsExplicitlySet()) {
|
||||
SaveOldViewBox(rootElement);
|
||||
rootElement->mViewBox.SetBaseValue(
|
||||
viewElement->mViewBox.GetBaseValue(), rootElement);
|
||||
} else {
|
||||
RestoreOldViewBox(rootElement);
|
||||
}
|
||||
if (viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
|
||||
SaveOldPreserveAspectRatio(rootElement);
|
||||
rootElement->mPreserveAspectRatio.SetBaseValue(
|
||||
viewElement->mPreserveAspectRatio.GetBaseValue(), rootElement);
|
||||
} else {
|
||||
RestoreOldPreserveAspectRatio(rootElement);
|
||||
}
|
||||
if (viewElement->mEnumAttributes[nsSVGViewElement::ZOOMANDPAN].IsExplicitlySet()) {
|
||||
SaveOldZoomAndPan(rootElement);
|
||||
rootElement->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].SetBaseValue(
|
||||
viewElement->mEnumAttributes[nsSVGViewElement::ZOOMANDPAN].GetBaseValue(), rootElement);
|
||||
} else {
|
||||
RestoreOldZoomAndPan(rootElement);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ProcessSVGViewSpec(aAnchorName, rootElement)) {
|
||||
return true;
|
||||
}
|
||||
RestoreOldViewBox(rootElement);
|
||||
RestoreOldPreserveAspectRatio(rootElement);
|
||||
RestoreOldZoomAndPan(rootElement);
|
||||
return false;
|
||||
}
|
85
content/svg/content/src/SVGFragmentIdentifier.h
Normal file
85
content/svg/content/src/SVGFragmentIdentifier.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Robert Longson <longsonr@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_SVGFRAGMENTIDENTIFIER_H__
|
||||
#define MOZILLA_SVGFRAGMENTIDENTIFIER_H__
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsSVGSVGElement;
|
||||
class nsSVGViewElement;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Implements support for parsing SVG fragment identifiers
|
||||
* http://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers
|
||||
*/
|
||||
class SVGFragmentIdentifier
|
||||
{
|
||||
// To prevent the class being instantiated
|
||||
SVGFragmentIdentifier() MOZ_DELETE;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Process the SVG fragment identifier, if there is one.
|
||||
* @return true if we found something we recognised
|
||||
*/
|
||||
static bool ProcessFragmentIdentifier(nsIDocument *aDocument,
|
||||
const nsAString &aAnchorName);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Parse an SVG ViewSpec and set applicable attributes on the root element.
|
||||
* @return true if there is a valid ViewSpec
|
||||
*/
|
||||
static bool ProcessSVGViewSpec(const nsAString &aViewSpec, nsSVGSVGElement *root);
|
||||
|
||||
// Save and restore things we override in case we want to go back e.g. the
|
||||
// user presses the back button
|
||||
static void SaveOldPreserveAspectRatio(nsSVGSVGElement *root);
|
||||
static void RestoreOldPreserveAspectRatio(nsSVGSVGElement *root);
|
||||
static void SaveOldViewBox(nsSVGSVGElement *root);
|
||||
static void RestoreOldViewBox(nsSVGSVGElement *root);
|
||||
static void SaveOldZoomAndPan(nsSVGSVGElement *root);
|
||||
static void RestoreOldZoomAndPan(nsSVGSVGElement *root);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_SVGFRAGMENTIDENTIFIER_H__
|
@ -422,6 +422,34 @@ nsSVGAnimationElement::IsNodeOfType(PRUint32 aFlags) const
|
||||
return !(aFlags & ~(eCONTENT | eANIMATION));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SVG utility methods
|
||||
|
||||
void
|
||||
nsSVGAnimationElement::ActivateByHyperlink()
|
||||
{
|
||||
FlushAnimations();
|
||||
|
||||
// The behavior for when the target is an animation element is defined in
|
||||
// SMIL Animation:
|
||||
// http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
|
||||
nsSMILTimeValue seekTime = mTimedElement.GetHyperlinkTime();
|
||||
if (seekTime.IsDefinite()) {
|
||||
nsSMILTimeContainer* timeContainer = GetTimeContainer();
|
||||
if (timeContainer) {
|
||||
timeContainer->SetCurrentTime(seekTime.GetMillis());
|
||||
AnimationNeedsResample();
|
||||
// As with nsSVGSVGElement::SetCurrentTime, we need to trigger
|
||||
// a synchronous sample now.
|
||||
FlushAnimations();
|
||||
}
|
||||
// else, silently fail. We mustn't be part of an SVG document fragment that
|
||||
// is attached to the document tree so there's nothing we can do here
|
||||
} else {
|
||||
BeginElement();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation helpers
|
||||
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
virtual nsSMILTimedElement& TimedElement();
|
||||
virtual nsSMILTimeContainer* GetTimeContainer();
|
||||
|
||||
// Utility methods for within SVG
|
||||
void ActivateByHyperlink();
|
||||
|
||||
protected:
|
||||
// nsSVGElement overrides
|
||||
bool IsEventName(nsIAtom* aName);
|
||||
|
@ -222,6 +222,9 @@ NS_NewSVGFEImageElement(nsIContent **aResult,
|
||||
nsresult
|
||||
NS_NewSVGFEDisplacementMapElement(nsIContent **aResult,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
nsresult
|
||||
NS_NewSVGViewElement(nsIContent **aResult,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
|
||||
nsresult
|
||||
NS_NewSVGAnimateElement(nsIContent **aResult,
|
||||
@ -370,6 +373,8 @@ NS_NewSVGElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
return NS_NewSVGMaskElement(aResult, aNodeInfo);
|
||||
if (name == nsGkAtoms::svgSwitch)
|
||||
return NS_NewSVGSwitchElement(aResult, aNodeInfo);
|
||||
if (name == nsGkAtoms::view)
|
||||
return NS_NewSVGViewElement(aResult, aNodeInfo);
|
||||
if (NS_SMILEnabled()) {
|
||||
if (name == nsGkAtoms::animate)
|
||||
return NS_NewSVGAnimateElement(aResult, aNodeInfo);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "DOMSVGMatrix.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsISVGChildFrame.h"
|
||||
#include "nsIDOMSVGPoint.h"
|
||||
@ -179,6 +180,43 @@ nsSVGGraphicElement::IsAttributeMapped(const nsIAtom* name) const
|
||||
nsSVGGraphicElementBase::IsAttributeMapped(name);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
nsSVGGraphicElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
PRInt32 aModType) const
|
||||
{
|
||||
nsChangeHint retval =
|
||||
nsSVGGraphicElementBase::GetAttributeChangeHint(aAttribute, aModType);
|
||||
if (aAttribute == nsGkAtoms::transform) {
|
||||
// We add nsChangeHint_UpdateOverflow so that nsFrame::UpdateOverflow()
|
||||
// will be called on us and our ancestors.
|
||||
nsIFrame* frame =
|
||||
const_cast<nsSVGGraphicElement*>(this)->GetPrimaryFrame();
|
||||
if (frame && frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
|
||||
// No need to do anything.
|
||||
} else if (aModType == nsIDOMMutationEvent::ADDITION ||
|
||||
aModType == nsIDOMMutationEvent::REMOVAL) {
|
||||
// In order to handle view creation/destruction and stacking context
|
||||
// changes, the code in nsStyleDisplay::CalcDifference uses
|
||||
// nsChangeHint_ReconstructFrame if the transform was added/removed.
|
||||
// XXXSDL Currently we don't need to reconstruct SVG frames when their
|
||||
// transform is set/unset since we don't currently create GFX layers for
|
||||
// SVG transforms, but we will after bug 614732 is fixed. Also change the
|
||||
// assertion in ApplyRenderingChangeToTree when we do that.
|
||||
NS_UpdateHint(retval, nsChangeHint_UpdateOverflow);
|
||||
} else {
|
||||
NS_ABORT_IF_FALSE(aModType == nsIDOMMutationEvent::MODIFICATION,
|
||||
"Unknown modification type.");
|
||||
// We just assume the old and new transforms are different.
|
||||
// XXXSDL Once we use GFX layers for SVG transforms, we will need to pass
|
||||
// the nsChangeHint_UpdateTransformLayer hint too. Note that the
|
||||
// assertion in ApplyRenderingChangeToTree will fail if that hint is
|
||||
// passed on nsIDOMMutationEvent::REMOVAL though.
|
||||
NS_UpdateHint(retval, nsChangeHint_UpdateOverflow);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGElement overrides
|
||||
|
||||
|
@ -62,6 +62,9 @@ public:
|
||||
// nsIContent interface
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||
|
||||
nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
PRInt32 aModType) const;
|
||||
|
||||
virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
|
||||
TransformTypes aWhich = eAllTransforms) const;
|
||||
virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix);
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "DOMSVGNumber.h"
|
||||
#include "DOMSVGLength.h"
|
||||
#include "nsSVGAngle.h"
|
||||
@ -204,7 +205,8 @@ nsSVGSVGElement::nsSVGSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
mPreviousScale(1.0f),
|
||||
mStartAnimationOnBindToTree(!aFromParser),
|
||||
mImageNeedsTransformInvalidation(false),
|
||||
mIsPaintingSVGImageElement(false)
|
||||
mIsPaintingSVGImageElement(false),
|
||||
mHasChildrenOnlyTransform(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -954,13 +956,6 @@ ComputeSynthesizedViewBoxDimension(const nsSVGLength2& aLength,
|
||||
gfxMatrix
|
||||
nsSVGSVGElement::GetViewBoxTransform() const
|
||||
{
|
||||
// Do we have an override preserveAspectRatio value?
|
||||
const SVGPreserveAspectRatio* overridePARPtr =
|
||||
GetImageOverridePreserveAspectRatio();
|
||||
|
||||
// May assign this to overridePARPtr if we have no viewBox but are faking one:
|
||||
SVGPreserveAspectRatio tmpPAR;
|
||||
|
||||
float viewportWidth, viewportHeight;
|
||||
if (IsInner()) {
|
||||
nsSVGSVGElement *ctx = GetCtx();
|
||||
@ -975,39 +970,8 @@ nsSVGSVGElement::GetViewBoxTransform() const
|
||||
return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
|
||||
}
|
||||
|
||||
nsSVGViewBoxRect viewBox;
|
||||
if (HasViewBox()) {
|
||||
viewBox = mViewBox.GetAnimValue();
|
||||
} else {
|
||||
viewBox.x = viewBox.y = 0.0f;
|
||||
if (ShouldSynthesizeViewBox()) {
|
||||
// Special case -- fake a viewBox, using height & width attrs.
|
||||
// (Use |this| as context, since if we get here, we're outermost <svg>.)
|
||||
viewBox.width =
|
||||
ComputeSynthesizedViewBoxDimension(mLengthAttributes[WIDTH],
|
||||
mViewportWidth, this);
|
||||
viewBox.height =
|
||||
ComputeSynthesizedViewBoxDimension(mLengthAttributes[HEIGHT],
|
||||
mViewportHeight, this);
|
||||
NS_ABORT_IF_FALSE(!overridePARPtr,
|
||||
"shouldn't have overridePAR if we're "
|
||||
"synthesizing a viewBox");
|
||||
|
||||
// If we're synthesizing a viewBox, use preserveAspectRatio="none";
|
||||
tmpPAR.SetAlign(nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE);
|
||||
|
||||
// (set the other pAR attributes too, just so they're initialized):
|
||||
tmpPAR.SetDefer(false);
|
||||
tmpPAR.SetMeetOrSlice(nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE);
|
||||
|
||||
overridePARPtr = &tmpPAR;
|
||||
} else {
|
||||
// No viewBox attribute, so we shouldn't auto-scale. This is equivalent
|
||||
// to having a viewBox that exactly matches our viewport size.
|
||||
viewBox.width = viewportWidth;
|
||||
viewBox.height = viewportHeight;
|
||||
}
|
||||
}
|
||||
nsSVGViewBoxRect viewBox =
|
||||
GetViewBoxWithSynthesis(viewportWidth, viewportHeight);
|
||||
|
||||
if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
|
||||
return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
|
||||
@ -1017,8 +981,34 @@ nsSVGSVGElement::GetViewBoxTransform() const
|
||||
viewportWidth, viewportHeight,
|
||||
viewBox.x, viewBox.y,
|
||||
viewBox.width, viewBox.height,
|
||||
overridePARPtr ? *overridePARPtr :
|
||||
mPreserveAspectRatio.GetAnimValue());
|
||||
GetPreserveAspectRatioWithOverride());
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSVGElement::ChildrenOnlyTransformChanged()
|
||||
{
|
||||
// Avoid wasteful calls:
|
||||
NS_ABORT_IF_FALSE(!(GetPrimaryFrame()->GetStateBits() &
|
||||
NS_STATE_SVG_NONDISPLAY_CHILD),
|
||||
"Non-display SVG frames don't maintain overflow rects");
|
||||
|
||||
bool hasChildrenOnlyTransform = HasViewBoxOrSyntheticViewBox() ||
|
||||
(IsRoot() && (mCurrentTranslate != nsSVGTranslatePoint(0.0f, 0.0f) ||
|
||||
mCurrentScale != 1.0f));
|
||||
|
||||
// XXXSDL Currently we don't destroy frames if
|
||||
// hasChildrenOnlyTransform != mHasChildrenOnlyTransform
|
||||
// but we should once we start using GFX layers for SVG transforms
|
||||
// (see the comment in nsSVGGraphicElement::GetAttributeChangeHint).
|
||||
|
||||
nsChangeHint changeHint =
|
||||
nsChangeHint(nsChangeHint_RepaintFrame |
|
||||
nsChangeHint_UpdateOverflow |
|
||||
nsChangeHint_ChildrenOnlyTransform);
|
||||
|
||||
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
|
||||
|
||||
mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1120,6 +1110,50 @@ nsSVGSVGElement::HasPreserveAspectRatio()
|
||||
mPreserveAspectRatio.IsAnimated();
|
||||
}
|
||||
|
||||
nsSVGViewBoxRect
|
||||
nsSVGSVGElement::GetViewBoxWithSynthesis(
|
||||
float aViewportWidth, float aViewportHeight) const
|
||||
{
|
||||
if (HasViewBox()) {
|
||||
return mViewBox.GetAnimValue();
|
||||
}
|
||||
|
||||
if (ShouldSynthesizeViewBox()) {
|
||||
// Special case -- fake a viewBox, using height & width attrs.
|
||||
// (Use |this| as context, since if we get here, we're outermost <svg>.)
|
||||
return nsSVGViewBoxRect(0, 0,
|
||||
ComputeSynthesizedViewBoxDimension(mLengthAttributes[WIDTH],
|
||||
mViewportWidth, this),
|
||||
ComputeSynthesizedViewBoxDimension(mLengthAttributes[HEIGHT],
|
||||
mViewportHeight, this));
|
||||
|
||||
}
|
||||
|
||||
// No viewBox attribute, so we shouldn't auto-scale. This is equivalent
|
||||
// to having a viewBox that exactly matches our viewport size.
|
||||
return nsSVGViewBoxRect(0, 0, aViewportWidth, aViewportHeight);
|
||||
}
|
||||
|
||||
SVGPreserveAspectRatio
|
||||
nsSVGSVGElement::GetPreserveAspectRatioWithOverride() const
|
||||
{
|
||||
if (GetCurrentDoc()->IsBeingUsedAsImage()) {
|
||||
const SVGPreserveAspectRatio *pAROverridePtr = GetPreserveAspectRatioProperty();
|
||||
if (pAROverridePtr) {
|
||||
return *pAROverridePtr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasViewBox() && ShouldSynthesizeViewBox()) {
|
||||
// If we're synthesizing a viewBox, use preserveAspectRatio="none";
|
||||
return SVGPreserveAspectRatio(
|
||||
nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE,
|
||||
nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE);
|
||||
}
|
||||
|
||||
return mPreserveAspectRatio.GetAnimValue();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGSVGElement
|
||||
|
||||
@ -1272,6 +1306,43 @@ ReleasePreserveAspectRatioPropertyValue(void* aObject, /* unused */
|
||||
delete valPtr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::
|
||||
SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR)
|
||||
{
|
||||
SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
|
||||
nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
|
||||
pAROverridePtr,
|
||||
ReleasePreserveAspectRatioPropertyValue);
|
||||
NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
|
||||
"Setting override value when it's already set...?");
|
||||
|
||||
if (NS_UNLIKELY(NS_FAILED(rv))) {
|
||||
// property-insertion failed (e.g. OOM in property-table code)
|
||||
delete pAROverridePtr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const SVGPreserveAspectRatio*
|
||||
nsSVGSVGElement::GetPreserveAspectRatioProperty() const
|
||||
{
|
||||
void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
|
||||
if (valPtr) {
|
||||
return static_cast<SVGPreserveAspectRatio*>(valPtr);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::ClearPreserveAspectRatioProperty()
|
||||
{
|
||||
void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
|
||||
delete static_cast<SVGPreserveAspectRatio*>(valPtr);
|
||||
return valPtr;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSVGElement::
|
||||
SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR)
|
||||
@ -1297,18 +1368,8 @@ nsSVGSVGElement::
|
||||
return; // Referring element defers to my own preserveAspectRatio value.
|
||||
}
|
||||
|
||||
SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
|
||||
nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
|
||||
pAROverridePtr,
|
||||
ReleasePreserveAspectRatioPropertyValue);
|
||||
NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
|
||||
"Setting override value when it's already set...?");
|
||||
|
||||
if (NS_LIKELY(NS_SUCCEEDED(rv))) {
|
||||
if (SetPreserveAspectRatioProperty(aPAR)) {
|
||||
mImageNeedsTransformInvalidation = true;
|
||||
} else {
|
||||
// property-insertion failed (e.g. OOM in property-table code)
|
||||
delete pAROverridePtr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1317,7 +1378,7 @@ nsSVGSVGElement::ClearImageOverridePreserveAspectRatio()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NS_ABORT_IF_FALSE(GetCurrentDoc()->IsBeingUsedAsImage(),
|
||||
"should only override preserveAspectRatio in images");
|
||||
"should only override image preserveAspectRatio in images");
|
||||
#endif
|
||||
|
||||
mIsPaintingSVGImageElement = false;
|
||||
@ -1328,27 +1389,11 @@ nsSVGSVGElement::ClearImageOverridePreserveAspectRatio()
|
||||
mImageNeedsTransformInvalidation = true;
|
||||
}
|
||||
|
||||
void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
|
||||
if (valPtr) {
|
||||
if (ClearPreserveAspectRatioProperty()) {
|
||||
mImageNeedsTransformInvalidation = true;
|
||||
delete static_cast<SVGPreserveAspectRatio*>(valPtr);
|
||||
}
|
||||
}
|
||||
|
||||
const SVGPreserveAspectRatio*
|
||||
nsSVGSVGElement::GetImageOverridePreserveAspectRatio() const
|
||||
{
|
||||
void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
|
||||
#ifdef DEBUG
|
||||
if (valPtr) {
|
||||
NS_ABORT_IF_FALSE(GetCurrentDoc()->IsBeingUsedAsImage(),
|
||||
"should only override preserveAspectRatio in images");
|
||||
}
|
||||
#endif
|
||||
|
||||
return static_cast<SVGPreserveAspectRatio*>(valPtr);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSVGElement::FlushImageTransformInvalidation()
|
||||
{
|
||||
@ -1361,3 +1406,78 @@ nsSVGSVGElement::FlushImageTransformInvalidation()
|
||||
mImageNeedsTransformInvalidation = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function, for freeing PRUint64 values stored in property table
|
||||
static void
|
||||
ReleaseViewBoxPropertyValue(void* aObject, /* unused */
|
||||
nsIAtom* aPropertyName, /* unused */
|
||||
void* aPropertyValue,
|
||||
void* aData /* unused */)
|
||||
{
|
||||
nsSVGViewBoxRect* valPtr =
|
||||
static_cast<nsSVGViewBoxRect*>(aPropertyValue);
|
||||
delete valPtr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::SetViewBoxProperty(const nsSVGViewBoxRect& aViewBox)
|
||||
{
|
||||
nsSVGViewBoxRect* pViewBoxOverridePtr = new nsSVGViewBoxRect(aViewBox);
|
||||
nsresult rv = SetProperty(nsGkAtoms::viewBox,
|
||||
pViewBoxOverridePtr,
|
||||
ReleaseViewBoxPropertyValue);
|
||||
NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
|
||||
"Setting override value when it's already set...?");
|
||||
|
||||
if (NS_UNLIKELY(NS_FAILED(rv))) {
|
||||
// property-insertion failed (e.g. OOM in property-table code)
|
||||
delete pViewBoxOverridePtr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsSVGViewBoxRect*
|
||||
nsSVGSVGElement::GetViewBoxProperty() const
|
||||
{
|
||||
void* valPtr = GetProperty(nsGkAtoms::viewBox);
|
||||
if (valPtr) {
|
||||
return static_cast<nsSVGViewBoxRect*>(valPtr);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::ClearViewBoxProperty()
|
||||
{
|
||||
void* valPtr = UnsetProperty(nsGkAtoms::viewBox);
|
||||
delete static_cast<nsSVGViewBoxRect*>(valPtr);
|
||||
return valPtr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::SetZoomAndPanProperty(PRUint16 aValue)
|
||||
{
|
||||
nsresult rv = SetProperty(nsGkAtoms::zoomAndPan, reinterpret_cast<void*>(aValue));
|
||||
NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
|
||||
"Setting override value when it's already set...?");
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
const PRUint16*
|
||||
nsSVGSVGElement::GetZoomAndPanProperty() const
|
||||
{
|
||||
void* valPtr = GetProperty(nsGkAtoms::zoomAndPan);
|
||||
if (valPtr) {
|
||||
return reinterpret_cast<PRUint16*>(valPtr);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGSVGElement::ClearZoomAndPanProperty()
|
||||
{
|
||||
return UnsetProperty(nsGkAtoms::viewBox);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,10 @@
|
||||
|
||||
class nsIDOMSVGMatrix;
|
||||
class nsSMILTimeContainer;
|
||||
class nsSVGViewElement;
|
||||
namespace mozilla {
|
||||
class SVGFragmentIdentifier;
|
||||
}
|
||||
|
||||
typedef nsSVGStylableElement nsSVGSVGElementBase;
|
||||
|
||||
@ -62,8 +66,15 @@ class nsSVGSVGElement;
|
||||
|
||||
class nsSVGTranslatePoint {
|
||||
public:
|
||||
nsSVGTranslatePoint(float aX, float aY) :
|
||||
mX(aX), mY(aY) {}
|
||||
nsSVGTranslatePoint()
|
||||
: mX(0.0f)
|
||||
, mY(0.0f)
|
||||
{}
|
||||
|
||||
nsSVGTranslatePoint(float aX, float aY)
|
||||
: mX(aX)
|
||||
, mY(aY)
|
||||
{}
|
||||
|
||||
void SetX(float aX)
|
||||
{ mX = aX; }
|
||||
@ -76,6 +87,10 @@ public:
|
||||
|
||||
nsresult ToDOMVal(nsSVGSVGElement *aElement, nsIDOMSVGPoint **aResult);
|
||||
|
||||
bool operator!=(const nsSVGTranslatePoint &rhs) const {
|
||||
return mX != rhs.mX || mY != rhs.mY;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct DOMVal : public nsIDOMSVGPoint {
|
||||
@ -127,8 +142,8 @@ class nsSVGSVGElement : public nsSVGSVGElementBase,
|
||||
friend class nsSVGOuterSVGFrame;
|
||||
friend class nsSVGInnerSVGFrame;
|
||||
friend class nsSVGImageFrame;
|
||||
friend class mozilla::SVGFragmentIdentifier;
|
||||
|
||||
protected:
|
||||
friend nsresult NS_NewSVGSVGElement(nsIContent **aResult,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser);
|
||||
@ -220,8 +235,28 @@ public:
|
||||
*/
|
||||
bool ShouldSynthesizeViewBox() const;
|
||||
|
||||
bool HasViewBoxOrSyntheticViewBox() const {
|
||||
return HasViewBox() || ShouldSynthesizeViewBox();
|
||||
}
|
||||
|
||||
gfxMatrix GetViewBoxTransform() const;
|
||||
|
||||
bool HasChildrenOnlyTransform() const {
|
||||
return mHasChildrenOnlyTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method notifies the style system that the overflow rects of our
|
||||
* immediate childrens' frames need to be updated. It is called by our own
|
||||
* frame when changes (e.g. to currentScale) cause our children-only
|
||||
* transform to change.
|
||||
*
|
||||
* The reason we have this method instead of overriding
|
||||
* GetAttributeChangeHint is because we need to act on non-attribute (e.g.
|
||||
* currentScale) changes in addition to attribute (e.g. viewBox) changes.
|
||||
*/
|
||||
void ChildrenOnlyTransformChanged();
|
||||
|
||||
// This services any pending notifications for the transform on on this root
|
||||
// <svg> node needing to be recalculated. (Only applicable in
|
||||
// SVG-as-an-image documents.)
|
||||
@ -243,14 +278,6 @@ public:
|
||||
virtual nsIDOMNode* AsDOMNode() { return this; }
|
||||
|
||||
private:
|
||||
// Methods for <image> elements to override my "PreserveAspectRatio" value.
|
||||
// These are private so that only our friends (nsSVGImageFrame in
|
||||
// particular) have access.
|
||||
void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
|
||||
void ClearImageOverridePreserveAspectRatio();
|
||||
const SVGPreserveAspectRatio* GetImageOverridePreserveAspectRatio() const;
|
||||
|
||||
protected:
|
||||
// nsSVGElement overrides
|
||||
bool IsEventName(nsIAtom* aName);
|
||||
|
||||
@ -261,6 +288,23 @@ protected:
|
||||
|
||||
// implementation helpers:
|
||||
|
||||
// Methods for <image> elements to override my "PreserveAspectRatio" value.
|
||||
// These are private so that only our friends (nsSVGImageFrame in
|
||||
// particular) have access.
|
||||
void SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR);
|
||||
void ClearImageOverridePreserveAspectRatio();
|
||||
|
||||
// Set/Clear properties to hold old or override versions of attributes
|
||||
bool SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR);
|
||||
const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
|
||||
bool ClearPreserveAspectRatioProperty();
|
||||
bool SetViewBoxProperty(const nsSVGViewBoxRect& aViewBox);
|
||||
const nsSVGViewBoxRect* GetViewBoxProperty() const;
|
||||
bool ClearViewBoxProperty();
|
||||
bool SetZoomAndPanProperty(PRUint16 aValue);
|
||||
const PRUint16* GetZoomAndPanProperty() const;
|
||||
bool ClearZoomAndPanProperty();
|
||||
|
||||
bool IsRoot() const {
|
||||
NS_ASSERTION((IsInDoc() && !GetParent()) ==
|
||||
(OwnerDoc() && (OwnerDoc()->GetRootElement() == this)),
|
||||
@ -288,7 +332,7 @@ protected:
|
||||
* parameters passed in instead.
|
||||
*/
|
||||
bool WillBeOutermostSVG(nsIContent* aParent,
|
||||
nsIContent* aBindingParent) const;
|
||||
nsIContent* aBindingParent) const;
|
||||
|
||||
// invalidate viewbox -> viewport xform & inform frames
|
||||
void InvalidateTransformNotifyFrame();
|
||||
@ -298,6 +342,19 @@ protected:
|
||||
// - a SMIL-animated value for the preserveAspectRatio attribute
|
||||
bool HasPreserveAspectRatio();
|
||||
|
||||
/**
|
||||
* Returns the explicit viewBox rect, if specified, or else a synthesized
|
||||
* viewBox, if appropriate, or else a viewBox matching the dimensions of the
|
||||
* SVG viewport.
|
||||
*/
|
||||
nsSVGViewBoxRect GetViewBoxWithSynthesis(
|
||||
float aViewportWidth, float aViewportHeight) const;
|
||||
/**
|
||||
* Returns the explicit or default preserveAspectRatio, unless we're
|
||||
* synthesizing a viewBox, in which case it returns the "none" value.
|
||||
*/
|
||||
SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const;
|
||||
|
||||
virtual LengthAttributesInfo GetLengthInfo();
|
||||
|
||||
enum { X, Y, WIDTH, HEIGHT };
|
||||
@ -349,6 +406,7 @@ protected:
|
||||
bool mStartAnimationOnBindToTree;
|
||||
bool mImageNeedsTransformInvalidation;
|
||||
bool mIsPaintingSVGImageElement;
|
||||
bool mHasChildrenOnlyTransform;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -124,16 +124,16 @@ nsSVGViewBox::SetAnimValue(float aX, float aY, float aWidth, float aHeight,
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGViewBox::SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
||||
nsSVGViewBox::SetBaseValue(const nsSVGViewBoxRect& aRect,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (mHasBaseVal && mBaseVal == nsSVGViewBoxRect(aX, aY, aWidth, aHeight)) {
|
||||
if (mHasBaseVal && mBaseVal == aRect) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeViewBox();
|
||||
|
||||
mBaseVal = nsSVGViewBoxRect(aX, aY, aWidth, aHeight);
|
||||
mBaseVal = aRect;
|
||||
mHasBaseVal = true;
|
||||
|
||||
aSVGElement->DidChangeViewBox(emptyOrOldValue);
|
||||
|
@ -86,9 +86,11 @@ public:
|
||||
|
||||
const nsSVGViewBoxRect& GetBaseValue() const
|
||||
{ return mBaseVal; }
|
||||
void SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
||||
void SetBaseValue(const nsSVGViewBoxRect& aRect,
|
||||
nsSVGElement *aSVGElement);
|
||||
|
||||
void SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
||||
nsSVGElement *aSVGElement)
|
||||
{ SetBaseValue(nsSVGViewBoxRect(aX, aY, aWidth, aHeight), aSVGElement); }
|
||||
const nsSVGViewBoxRect& GetAnimValue() const
|
||||
{ return mAnimVal ? *mAnimVal : mBaseVal; }
|
||||
void SetAnimValue(float aX, float aY, float aWidth, float aHeight,
|
||||
|
169
content/svg/content/src/nsSVGViewElement.cpp
Normal file
169
content/svg/content/src/nsSVGViewElement.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Robert Longson.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsSVGViewElement.h"
|
||||
#include "DOMSVGStringList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsSVGElement::StringListInfo nsSVGViewElement::sStringListInfo[1] =
|
||||
{
|
||||
{ &nsGkAtoms::viewTarget }
|
||||
};
|
||||
|
||||
nsSVGEnumMapping nsSVGViewElement::sZoomAndPanMap[] = {
|
||||
{&nsGkAtoms::disable, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_DISABLE},
|
||||
{&nsGkAtoms::magnify, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY},
|
||||
{nsnull, 0}
|
||||
};
|
||||
|
||||
nsSVGElement::EnumInfo nsSVGViewElement::sEnumInfo[1] =
|
||||
{
|
||||
{ &nsGkAtoms::zoomAndPan,
|
||||
sZoomAndPanMap,
|
||||
nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_NS_NEW_SVG_ELEMENT(View)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsSVGViewElement,nsSVGViewElementBase)
|
||||
NS_IMPL_RELEASE_INHERITED(nsSVGViewElement,nsSVGViewElementBase)
|
||||
|
||||
DOMCI_NODE_DATA(SVGViewElement, nsSVGViewElement)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(nsSVGViewElement)
|
||||
NS_NODE_INTERFACE_TABLE6(nsSVGViewElement, nsIDOMNode, nsIDOMElement,
|
||||
nsIDOMSVGElement, nsIDOMSVGViewElement,
|
||||
nsIDOMSVGFitToViewBox,
|
||||
nsIDOMSVGZoomAndPan)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGViewElement)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsSVGViewElementBase)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
nsSVGViewElement::nsSVGViewElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: nsSVGViewElementBase(aNodeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMNode methods
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGViewElement)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGZoomAndPan methods
|
||||
|
||||
/* attribute unsigned short zoomAndPan; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGViewElement::GetZoomAndPan(PRUint16 *aZoomAndPan)
|
||||
{
|
||||
*aZoomAndPan = mEnumAttributes[ZOOMANDPAN].GetAnimValue();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGViewElement::SetZoomAndPan(PRUint16 aZoomAndPan)
|
||||
{
|
||||
if (aZoomAndPan == nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_DISABLE ||
|
||||
aZoomAndPan == nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY) {
|
||||
mEnumAttributes[ZOOMANDPAN].SetBaseValue(aZoomAndPan, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_DOM_SVG_INVALID_VALUE_ERR;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGFitToViewBox methods
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGViewElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
|
||||
{
|
||||
return mViewBox.ToDOMAnimatedRect(aViewBox, this);
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGViewElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
|
||||
**aPreserveAspectRatio)
|
||||
{
|
||||
return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGViewElement methods
|
||||
|
||||
/* readonly attribute nsIDOMSVGStringList viewTarget; */
|
||||
NS_IMETHODIMP nsSVGViewElement::GetViewTarget(nsIDOMSVGStringList * *aViewTarget)
|
||||
{
|
||||
*aViewTarget = DOMSVGStringList::GetDOMWrapper(
|
||||
&mStringListAttributes[VIEW_TARGET], this, false, VIEW_TARGET).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGElement methods
|
||||
|
||||
nsSVGElement::EnumAttributesInfo
|
||||
nsSVGViewElement::GetEnumInfo()
|
||||
{
|
||||
return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
|
||||
ArrayLength(sEnumInfo));
|
||||
}
|
||||
|
||||
nsSVGViewBox *
|
||||
nsSVGViewElement::GetViewBox()
|
||||
{
|
||||
return &mViewBox;
|
||||
}
|
||||
|
||||
SVGAnimatedPreserveAspectRatio *
|
||||
nsSVGViewElement::GetPreserveAspectRatio()
|
||||
{
|
||||
return &mPreserveAspectRatio;
|
||||
}
|
||||
|
||||
nsSVGElement::StringListAttributesInfo
|
||||
nsSVGViewElement::GetStringListInfo()
|
||||
{
|
||||
return StringListAttributesInfo(mStringListAttributes, sStringListInfo,
|
||||
ArrayLength(sStringListInfo));
|
||||
}
|
106
content/svg/content/src/nsSVGViewElement.h
Normal file
106
content/svg/content/src/nsSVGViewElement.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Robert Longson.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __NS_SVGVIEWELEMENT_H__
|
||||
#define __NS_SVGVIEWELEMENT_H__
|
||||
|
||||
#include "nsIDOMSVGViewElement.h"
|
||||
#include "nsIDOMSVGFitToViewBox.h"
|
||||
#include "nsIDOMSVGZoomAndPan.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsSVGEnum.h"
|
||||
#include "nsSVGViewBox.h"
|
||||
#include "SVGAnimatedPreserveAspectRatio.h"
|
||||
#include "SVGStringList.h"
|
||||
|
||||
namespace mozilla {
|
||||
class SVGFragmentIdentifier;
|
||||
}
|
||||
|
||||
typedef nsSVGElement nsSVGViewElementBase;
|
||||
|
||||
class nsSVGViewElement : public nsSVGViewElementBase,
|
||||
public nsIDOMSVGViewElement,
|
||||
public nsIDOMSVGFitToViewBox,
|
||||
public nsIDOMSVGZoomAndPan
|
||||
{
|
||||
friend class mozilla::SVGFragmentIdentifier;
|
||||
friend nsresult NS_NewSVGViewElement(nsIContent **aResult,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
nsSVGViewElement(already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
|
||||
public:
|
||||
// interfaces:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMSVGVIEWELEMENT
|
||||
NS_DECL_NSIDOMSVGFITTOVIEWBOX
|
||||
NS_DECL_NSIDOMSVGZOOMANDPAN
|
||||
|
||||
// xxx If xpcom allowed virtual inheritance we wouldn't need to
|
||||
// forward here :-(
|
||||
NS_FORWARD_NSIDOMNODE(nsSVGViewElementBase::)
|
||||
NS_FORWARD_NSIDOMELEMENT(nsSVGViewElementBase::)
|
||||
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGViewElementBase::)
|
||||
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
virtual nsXPCClassInfo* GetClassInfo();
|
||||
|
||||
virtual nsIDOMNode* AsDOMNode() { return this; }
|
||||
private:
|
||||
|
||||
// nsSVGElement overrides
|
||||
|
||||
virtual EnumAttributesInfo GetEnumInfo();
|
||||
|
||||
enum { ZOOMANDPAN };
|
||||
nsSVGEnum mEnumAttributes[1];
|
||||
static nsSVGEnumMapping sZoomAndPanMap[];
|
||||
static EnumInfo sEnumInfo[1];
|
||||
|
||||
virtual nsSVGViewBox *GetViewBox();
|
||||
virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio();
|
||||
|
||||
nsSVGViewBox mViewBox;
|
||||
SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
|
||||
|
||||
virtual StringListAttributesInfo GetStringListInfo();
|
||||
|
||||
enum { VIEW_TARGET };
|
||||
SVGStringList mStringListAttributes[1];
|
||||
static StringListInfo sStringListInfo[1];
|
||||
};
|
||||
|
||||
#endif
|
@ -647,126 +647,10 @@ struct keyCodeData {
|
||||
// XXX: be sure to check this periodically for new symbol additions!
|
||||
static const keyCodeData gKeyCodes[] = {
|
||||
|
||||
#define KEYCODE_ENTRY(str) {#str, sizeof(#str) - 1, nsIDOMKeyEvent::DOM_##str}
|
||||
#define KEYCODE_ENTRY2(str, code) {str, sizeof(str) - 1, code}
|
||||
|
||||
KEYCODE_ENTRY(VK_CANCEL),
|
||||
KEYCODE_ENTRY2("VK_BACK", nsIDOMKeyEvent::DOM_VK_BACK_SPACE),
|
||||
KEYCODE_ENTRY(VK_TAB),
|
||||
KEYCODE_ENTRY(VK_CLEAR),
|
||||
KEYCODE_ENTRY(VK_RETURN),
|
||||
KEYCODE_ENTRY(VK_ENTER),
|
||||
KEYCODE_ENTRY(VK_SHIFT),
|
||||
KEYCODE_ENTRY(VK_CONTROL),
|
||||
KEYCODE_ENTRY(VK_ALT),
|
||||
KEYCODE_ENTRY(VK_PAUSE),
|
||||
KEYCODE_ENTRY(VK_CAPS_LOCK),
|
||||
KEYCODE_ENTRY(VK_ESCAPE),
|
||||
KEYCODE_ENTRY(VK_SPACE),
|
||||
KEYCODE_ENTRY(VK_PAGE_UP),
|
||||
KEYCODE_ENTRY(VK_PAGE_DOWN),
|
||||
KEYCODE_ENTRY(VK_END),
|
||||
KEYCODE_ENTRY(VK_HOME),
|
||||
KEYCODE_ENTRY(VK_LEFT),
|
||||
KEYCODE_ENTRY(VK_UP),
|
||||
KEYCODE_ENTRY(VK_RIGHT),
|
||||
KEYCODE_ENTRY(VK_DOWN),
|
||||
KEYCODE_ENTRY(VK_PRINTSCREEN),
|
||||
KEYCODE_ENTRY(VK_INSERT),
|
||||
KEYCODE_ENTRY(VK_HELP),
|
||||
KEYCODE_ENTRY(VK_DELETE),
|
||||
KEYCODE_ENTRY(VK_0),
|
||||
KEYCODE_ENTRY(VK_1),
|
||||
KEYCODE_ENTRY(VK_2),
|
||||
KEYCODE_ENTRY(VK_3),
|
||||
KEYCODE_ENTRY(VK_4),
|
||||
KEYCODE_ENTRY(VK_5),
|
||||
KEYCODE_ENTRY(VK_6),
|
||||
KEYCODE_ENTRY(VK_7),
|
||||
KEYCODE_ENTRY(VK_8),
|
||||
KEYCODE_ENTRY(VK_9),
|
||||
KEYCODE_ENTRY(VK_SEMICOLON),
|
||||
KEYCODE_ENTRY(VK_EQUALS),
|
||||
KEYCODE_ENTRY(VK_A),
|
||||
KEYCODE_ENTRY(VK_B),
|
||||
KEYCODE_ENTRY(VK_C),
|
||||
KEYCODE_ENTRY(VK_D),
|
||||
KEYCODE_ENTRY(VK_E),
|
||||
KEYCODE_ENTRY(VK_F),
|
||||
KEYCODE_ENTRY(VK_G),
|
||||
KEYCODE_ENTRY(VK_H),
|
||||
KEYCODE_ENTRY(VK_I),
|
||||
KEYCODE_ENTRY(VK_J),
|
||||
KEYCODE_ENTRY(VK_K),
|
||||
KEYCODE_ENTRY(VK_L),
|
||||
KEYCODE_ENTRY(VK_M),
|
||||
KEYCODE_ENTRY(VK_N),
|
||||
KEYCODE_ENTRY(VK_O),
|
||||
KEYCODE_ENTRY(VK_P),
|
||||
KEYCODE_ENTRY(VK_Q),
|
||||
KEYCODE_ENTRY(VK_R),
|
||||
KEYCODE_ENTRY(VK_S),
|
||||
KEYCODE_ENTRY(VK_T),
|
||||
KEYCODE_ENTRY(VK_U),
|
||||
KEYCODE_ENTRY(VK_V),
|
||||
KEYCODE_ENTRY(VK_W),
|
||||
KEYCODE_ENTRY(VK_X),
|
||||
KEYCODE_ENTRY(VK_Y),
|
||||
KEYCODE_ENTRY(VK_Z),
|
||||
KEYCODE_ENTRY(VK_NUMPAD0),
|
||||
KEYCODE_ENTRY(VK_NUMPAD1),
|
||||
KEYCODE_ENTRY(VK_NUMPAD2),
|
||||
KEYCODE_ENTRY(VK_NUMPAD3),
|
||||
KEYCODE_ENTRY(VK_NUMPAD4),
|
||||
KEYCODE_ENTRY(VK_NUMPAD5),
|
||||
KEYCODE_ENTRY(VK_NUMPAD6),
|
||||
KEYCODE_ENTRY(VK_NUMPAD7),
|
||||
KEYCODE_ENTRY(VK_NUMPAD8),
|
||||
KEYCODE_ENTRY(VK_NUMPAD9),
|
||||
KEYCODE_ENTRY(VK_MULTIPLY),
|
||||
KEYCODE_ENTRY(VK_ADD),
|
||||
KEYCODE_ENTRY(VK_SEPARATOR),
|
||||
KEYCODE_ENTRY(VK_SUBTRACT),
|
||||
KEYCODE_ENTRY(VK_DECIMAL),
|
||||
KEYCODE_ENTRY(VK_DIVIDE),
|
||||
KEYCODE_ENTRY(VK_F1),
|
||||
KEYCODE_ENTRY(VK_F2),
|
||||
KEYCODE_ENTRY(VK_F3),
|
||||
KEYCODE_ENTRY(VK_F4),
|
||||
KEYCODE_ENTRY(VK_F5),
|
||||
KEYCODE_ENTRY(VK_F6),
|
||||
KEYCODE_ENTRY(VK_F7),
|
||||
KEYCODE_ENTRY(VK_F8),
|
||||
KEYCODE_ENTRY(VK_F9),
|
||||
KEYCODE_ENTRY(VK_F10),
|
||||
KEYCODE_ENTRY(VK_F11),
|
||||
KEYCODE_ENTRY(VK_F12),
|
||||
KEYCODE_ENTRY(VK_F13),
|
||||
KEYCODE_ENTRY(VK_F14),
|
||||
KEYCODE_ENTRY(VK_F15),
|
||||
KEYCODE_ENTRY(VK_F16),
|
||||
KEYCODE_ENTRY(VK_F17),
|
||||
KEYCODE_ENTRY(VK_F18),
|
||||
KEYCODE_ENTRY(VK_F19),
|
||||
KEYCODE_ENTRY(VK_F20),
|
||||
KEYCODE_ENTRY(VK_F21),
|
||||
KEYCODE_ENTRY(VK_F22),
|
||||
KEYCODE_ENTRY(VK_F23),
|
||||
KEYCODE_ENTRY(VK_F24),
|
||||
KEYCODE_ENTRY(VK_NUM_LOCK),
|
||||
KEYCODE_ENTRY(VK_SCROLL_LOCK),
|
||||
KEYCODE_ENTRY(VK_COMMA),
|
||||
KEYCODE_ENTRY(VK_PERIOD),
|
||||
KEYCODE_ENTRY(VK_SLASH),
|
||||
KEYCODE_ENTRY(VK_BACK_QUOTE),
|
||||
KEYCODE_ENTRY(VK_OPEN_BRACKET),
|
||||
KEYCODE_ENTRY(VK_BACK_SLASH),
|
||||
KEYCODE_ENTRY(VK_CLOSE_BRACKET),
|
||||
KEYCODE_ENTRY(VK_QUOTE)
|
||||
|
||||
#undef KEYCODE_ENTRY
|
||||
#undef KEYCODE_ENTRY2
|
||||
|
||||
#define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
|
||||
{ #aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode }
|
||||
#include "nsVKList.h"
|
||||
#undef NS_DEFINE_VK
|
||||
};
|
||||
|
||||
PRInt32 nsXBLPrototypeHandler::GetMatchingKeyCode(const nsAString& aKeyName)
|
||||
|
@ -436,6 +436,7 @@
|
||||
#include "nsIDOMSVGUnitTypes.h"
|
||||
#include "nsIDOMSVGURIReference.h"
|
||||
#include "nsIDOMSVGUseElement.h"
|
||||
#include "nsIDOMSVGViewElement.h"
|
||||
#include "nsIDOMSVGZoomAndPan.h"
|
||||
#include "nsIDOMSVGZoomEvent.h"
|
||||
|
||||
@ -1215,6 +1216,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
ELEMENT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGUseElement, nsElementSH,
|
||||
ELEMENT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGViewElement, nsElementSH,
|
||||
ELEMENT_SCRIPTABLE_FLAGS)
|
||||
|
||||
// other SVG classes
|
||||
NS_DEFINE_CLASSINFO_DATA(SVGAngle, nsDOMGenericSH,
|
||||
@ -3677,6 +3680,12 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(SVGViewElement, nsIDOMSVGViewElement)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGFitToViewBox)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGZoomAndPan)
|
||||
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
// other SVG classes
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(SVGAngle, nsIDOMSVGAngle)
|
||||
|
@ -296,6 +296,7 @@ DOMCI_CLASS(SVGTitleElement)
|
||||
DOMCI_CLASS(SVGTSpanElement)
|
||||
DOMCI_CLASS(SVGUnknownElement)
|
||||
DOMCI_CLASS(SVGUseElement)
|
||||
DOMCI_CLASS(SVGViewElement)
|
||||
|
||||
// other SVG classes
|
||||
DOMCI_CLASS(SVGAngle)
|
||||
|
@ -56,6 +56,7 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
||||
const unsigned long DOM_VK_CAPS_LOCK = 0x14;
|
||||
const unsigned long DOM_VK_KANA = 0x15;
|
||||
const unsigned long DOM_VK_HANGUL = 0x15;
|
||||
const unsigned long DOM_VK_EISU = 0x16; // Japanese Mac keyboard only
|
||||
const unsigned long DOM_VK_JUNJA = 0x17;
|
||||
const unsigned long DOM_VK_FINAL = 0x18;
|
||||
const unsigned long DOM_VK_HANJA = 0x19;
|
||||
@ -93,8 +94,13 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
||||
const unsigned long DOM_VK_8 = 0x38;
|
||||
const unsigned long DOM_VK_9 = 0x39;
|
||||
|
||||
const unsigned long DOM_VK_COLON = 0x3A;
|
||||
const unsigned long DOM_VK_SEMICOLON = 0x3B;
|
||||
const unsigned long DOM_VK_LESS_THAN = 0x3C;
|
||||
const unsigned long DOM_VK_EQUALS = 0x3D;
|
||||
const unsigned long DOM_VK_GREATER_THAN = 0x3E;
|
||||
const unsigned long DOM_VK_QUESTION_MARK = 0x3F;
|
||||
const unsigned long DOM_VK_AT = 0x40;
|
||||
|
||||
// DOM_VK_A - DOM_VK_Z match their ascii values
|
||||
const unsigned long DOM_VK_A = 0x41;
|
||||
@ -124,9 +130,11 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
||||
const unsigned long DOM_VK_Y = 0x59;
|
||||
const unsigned long DOM_VK_Z = 0x5A;
|
||||
|
||||
const unsigned long DOM_VK_WIN = 0x5B;
|
||||
const unsigned long DOM_VK_CONTEXT_MENU = 0x5D;
|
||||
const unsigned long DOM_VK_SLEEP = 0x5F;
|
||||
|
||||
// Numpad keys
|
||||
const unsigned long DOM_VK_NUMPAD0 = 0x60;
|
||||
const unsigned long DOM_VK_NUMPAD1 = 0x61;
|
||||
const unsigned long DOM_VK_NUMPAD2 = 0x62;
|
||||
@ -143,6 +151,7 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
||||
const unsigned long DOM_VK_SUBTRACT = 0x6D;
|
||||
const unsigned long DOM_VK_DECIMAL = 0x6E;
|
||||
const unsigned long DOM_VK_DIVIDE = 0x6F;
|
||||
|
||||
const unsigned long DOM_VK_F1 = 0x70;
|
||||
const unsigned long DOM_VK_F2 = 0x71;
|
||||
const unsigned long DOM_VK_F3 = 0x72;
|
||||
@ -171,16 +180,37 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
||||
const unsigned long DOM_VK_NUM_LOCK = 0x90;
|
||||
const unsigned long DOM_VK_SCROLL_LOCK = 0x91;
|
||||
|
||||
const unsigned long DOM_VK_CIRCUMFLEX = 0xA0;
|
||||
const unsigned long DOM_VK_EXCLAMATION = 0xA1;
|
||||
const unsigned long DOM_VK_DOUBLE_QUOTE = 0xA2;
|
||||
const unsigned long DOM_VK_HASH = 0xA3;
|
||||
const unsigned long DOM_VK_DOLLAR = 0xA4;
|
||||
const unsigned long DOM_VK_PERCENT = 0xA5;
|
||||
const unsigned long DOM_VK_AMPERSAND = 0xA6;
|
||||
const unsigned long DOM_VK_UNDERSCORE = 0xA7;
|
||||
const unsigned long DOM_VK_OPEN_PAREN = 0xA8;
|
||||
const unsigned long DOM_VK_CLOSE_PAREN = 0xA9;
|
||||
const unsigned long DOM_VK_ASTERISK = 0xAA;
|
||||
const unsigned long DOM_VK_PLUS = 0xAB;
|
||||
const unsigned long DOM_VK_PIPE = 0xAC;
|
||||
const unsigned long DOM_VK_HYPHEN_MINUS = 0xAD;
|
||||
|
||||
const unsigned long DOM_VK_OPEN_CURLY_BRACKET = 0xAE;
|
||||
const unsigned long DOM_VK_CLOSE_CURLY_BRACKET = 0xAF;
|
||||
|
||||
const unsigned long DOM_VK_TILDE = 0xB0;
|
||||
|
||||
const unsigned long DOM_VK_COMMA = 0xBC;
|
||||
const unsigned long DOM_VK_PERIOD = 0xBE;
|
||||
const unsigned long DOM_VK_SLASH = 0xBF;
|
||||
const unsigned long DOM_VK_BACK_QUOTE = 0xC0;
|
||||
const unsigned long DOM_VK_OPEN_BRACKET = 0xDB;
|
||||
const unsigned long DOM_VK_OPEN_BRACKET = 0xDB; // square bracket
|
||||
const unsigned long DOM_VK_BACK_SLASH = 0xDC;
|
||||
const unsigned long DOM_VK_CLOSE_BRACKET = 0xDD;
|
||||
const unsigned long DOM_VK_QUOTE = 0xDE;
|
||||
const unsigned long DOM_VK_CLOSE_BRACKET = 0xDD; // square bracket
|
||||
const unsigned long DOM_VK_QUOTE = 0xDE; // Apostrophe
|
||||
|
||||
const unsigned long DOM_VK_META = 0xE0;
|
||||
const unsigned long DOM_VK_ALTGR = 0xE1;
|
||||
|
||||
readonly attribute unsigned long charCode;
|
||||
readonly attribute unsigned long keyCode;
|
||||
|
@ -131,6 +131,7 @@ XPIDLSRCS = \
|
||||
nsIDOMSVGURIReference.idl \
|
||||
nsIDOMSVGUnitTypes.idl \
|
||||
nsIDOMSVGUseElement.idl \
|
||||
nsIDOMSVGViewElement.idl \
|
||||
nsIDOMSVGViewSpec.idl \
|
||||
nsIDOMSVGZoomAndPan.idl \
|
||||
nsIDOMSVGZoomEvent.idl \
|
||||
|
57
dom/interfaces/svg/nsIDOMSVGViewElement.idl
Normal file
57
dom/interfaces/svg/nsIDOMSVGViewElement.idl
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Robert Longson
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIDOMSVGElement.idl"
|
||||
#include "nsIDOMSVGStringList.idl"
|
||||
|
||||
[scriptable, uuid(4b02f970-a916-4b9d-b83f-eecef658266b)]
|
||||
interface nsIDOMSVGViewElement
|
||||
: nsIDOMSVGElement
|
||||
/*
|
||||
The SVG DOM makes use of multiple interface inheritance.
|
||||
Since XPCOM only supports single interface inheritance,
|
||||
the best thing that we can do is to promise that whenever
|
||||
an object implements _this_ interface it will also
|
||||
implement the following interfaces. (We then have to QI to
|
||||
hop between them.)
|
||||
|
||||
nsIDOMSVGExternalResourcesRequired,
|
||||
nsIDOMSVGFitToViewBox,
|
||||
nsIDOMSVGZoomAndPan
|
||||
*/
|
||||
{
|
||||
readonly attribute nsIDOMSVGStringList viewTarget;
|
||||
};
|
||||
|
@ -13,13 +13,3 @@ assertEq(JSON.stringify({2:'ponies', unicorns:'not real'}, array), "{\"2\":\"pon
|
||||
assertEq(JSON.stringify({42:true, ponies:true, unicorns:'sad'}, [number, string]), "{\"42\":true,\"ponies\":true}");
|
||||
assertEq(JSON.stringify({a:true,b:false}, undefined, number), "{\n \"a\": true,\n \"b\": false\n}");
|
||||
assertEq(JSON.stringify({a:true,b:false}, undefined, string), "{\nponies\"a\": true,\nponies\"b\": false\n}");
|
||||
|
||||
var o = Proxy.create({getPropertyDescriptor:function(name) {}}, Object.prototype);
|
||||
var threw = false;
|
||||
try {
|
||||
print([].concat(o).toString());
|
||||
} catch(e) {
|
||||
assertEq(e instanceof TypeError, true);
|
||||
threw = true;
|
||||
}
|
||||
assertEq(threw, true);
|
||||
|
@ -1,12 +0,0 @@
|
||||
otherGlobal = newGlobal("same-compartment");
|
||||
otherGlobal.poison = Proxy.create({});
|
||||
callee = new otherGlobal.Function("return this.poison;");
|
||||
|
||||
var caught = false;
|
||||
try {
|
||||
[1,2,3,4,5,6,7,8].sort(callee);
|
||||
} catch(e) {
|
||||
assertEq(e instanceof Error, true);
|
||||
caught = true;
|
||||
}
|
||||
assertEq(caught, true);
|
@ -1,28 +0,0 @@
|
||||
x = Proxy.create((function () {
|
||||
return {
|
||||
get: function () {}
|
||||
}
|
||||
}()), Object.e)
|
||||
|
||||
var hit = false;
|
||||
|
||||
try {
|
||||
Function("\
|
||||
for(var a = 0; a < 2; ++a) {\
|
||||
if (a == 0) {}\
|
||||
else {\
|
||||
x > x\
|
||||
}\
|
||||
}\
|
||||
")()
|
||||
} catch (e) {
|
||||
hit = true;
|
||||
|
||||
var str = String(e);
|
||||
var match = (str == "TypeError: x is not a function" ||
|
||||
str == "TypeError: can't convert x to number");
|
||||
|
||||
assertEq(match, true);
|
||||
}
|
||||
|
||||
assertEq(hit, true);
|
@ -68,7 +68,7 @@
|
||||
namespace js {
|
||||
|
||||
class AutoPropDescArrayRooter;
|
||||
class ProxyHandler;
|
||||
class BaseProxyHandler;
|
||||
class CallObject;
|
||||
struct GCMarker;
|
||||
struct NativeIterator;
|
||||
|
@ -45,12 +45,13 @@
|
||||
#include "jsgc.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsproxy.h"
|
||||
#include "jsscope.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsinferinlines.h"
|
||||
@ -96,16 +97,16 @@ OperationInProgress(JSContext *cx, JSObject *proxy)
|
||||
}
|
||||
#endif
|
||||
|
||||
ProxyHandler::ProxyHandler(void *family) : mFamily(family)
|
||||
BaseProxyHandler::BaseProxyHandler(void *family) : mFamily(family)
|
||||
{
|
||||
}
|
||||
|
||||
ProxyHandler::~ProxyHandler()
|
||||
BaseProxyHandler::~BaseProxyHandler()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
BaseProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
AutoPropertyDescriptorRooter desc(cx);
|
||||
@ -116,7 +117,7 @@ ProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
AutoPropertyDescriptorRooter desc(cx);
|
||||
@ -127,7 +128,7 @@ ProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
||||
BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
AutoPropertyDescriptorRooter desc(cx);
|
||||
@ -154,7 +155,7 @@ ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, V
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present)
|
||||
BaseProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present)
|
||||
{
|
||||
RootedVarObject proxy(cx, proxy_);
|
||||
RootedVarObject receiver(cx, receiver_);
|
||||
@ -175,7 +176,7 @@ ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *rec
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
|
||||
BaseProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
|
||||
Value *vp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
@ -245,7 +246,7 @@ ProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, b
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||
BaseProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
JS_ASSERT(props.length() == 0);
|
||||
@ -272,7 +273,7 @@ ProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
|
||||
BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
|
||||
{
|
||||
RootedVarObject proxy(cx, proxy_);
|
||||
|
||||
@ -286,66 +287,196 @@ ProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp
|
||||
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
|
||||
}
|
||||
|
||||
JSString *
|
||||
ProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
|
||||
bool
|
||||
BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *vp)
|
||||
{
|
||||
JS_ASSERT(proxy->isProxy());
|
||||
|
||||
return JS_NewStringCopyZ(cx, IsFunctionProxy(proxy)
|
||||
? "[object Function]"
|
||||
: "[object Object]");
|
||||
}
|
||||
|
||||
JSString *
|
||||
ProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
|
||||
{
|
||||
JS_ASSERT(proxy->isProxy());
|
||||
Value fval = GetCall(proxy);
|
||||
if (IsFunctionProxy(proxy) &&
|
||||
(fval.isPrimitive() || !fval.toObject().isFunction())) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, js_toString_str,
|
||||
"object");
|
||||
return NULL;
|
||||
}
|
||||
return fun_toStringHelper(cx, &fval.toObject(), indent);
|
||||
Value v = UndefinedValue();
|
||||
js_ReportIsNotFunction(cx, &v, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g)
|
||||
BaseProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval)
|
||||
{
|
||||
Value v = UndefinedValue();
|
||||
js_ReportIsNotFunction(cx, &v, JSV2F_CONSTRUCT);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString *
|
||||
BaseProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Object_str, js_toString_str,
|
||||
"object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSString *
|
||||
BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, js_toString_str,
|
||||
"object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
|
||||
RegExpGuard *g)
|
||||
{
|
||||
JS_NOT_REACHED("This should have been a wrapped regexp");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
|
||||
BaseProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
|
||||
Value *vp)
|
||||
{
|
||||
return DefaultValue(cx, RootedVarObject(cx, proxy), hint, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
|
||||
BaseProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
|
||||
{
|
||||
vp->setMagic(JS_NO_ITER_VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp)
|
||||
BaseProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
RootedVarValue rval(cx);
|
||||
JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.address());
|
||||
ReportIncompatibleMethod(cx, args, clasp);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
|
||||
JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSType
|
||||
BaseProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BaseProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BaseProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
||||
{
|
||||
}
|
||||
|
||||
IndirectProxyHandler::IndirectProxyHandler(void *family) : BaseProxyHandler(family)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
|
||||
jsid id, bool set,
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
return JS_GetPropertyDescriptorById(cx, GetProxyTargetObject(proxy), id,
|
||||
JSRESOLVE_QUALIFIED, desc);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSPropertyDescriptor *desc)
|
||||
{
|
||||
// If obj is a proxy, we can do better than just guessing. This is
|
||||
// important for certain types of wrappers that wrap other wrappers.
|
||||
if (obj->isProxy())
|
||||
return Proxy::getOwnPropertyDescriptor(cx, obj, id, flags & JSRESOLVE_ASSIGNING, desc);
|
||||
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
|
||||
return false;
|
||||
if (desc->obj != obj)
|
||||
desc->obj = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
|
||||
jsid id, bool set,
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
return GetOwnPropertyDescriptor(cx, GetProxyTargetObject(proxy), id,
|
||||
JSRESOLVE_QUALIFIED, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
return JS_DefinePropertyById(cx, GetProxyTargetObject(proxy), id,
|
||||
desc->value, desc->getter, desc->setter,
|
||||
desc->attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props)
|
||||
{
|
||||
return GetPropertyNames(cx, GetProxyTargetObject(proxy),
|
||||
JSITER_OWNONLY | JSITER_HIDDEN, &props);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
Value v;
|
||||
if (!JS_DeletePropertyById2(cx, GetProxyTargetObject(proxy), id, &v))
|
||||
return false;
|
||||
JSBool b;
|
||||
if (!JS_ValueToBoolean(cx, v, &b))
|
||||
return false;
|
||||
*bp = !!b;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props)
|
||||
{
|
||||
return GetPropertyNames(cx, GetProxyTargetObject(proxy), 0, &props);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *vp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
AutoValueRooter rval(cx);
|
||||
JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr());
|
||||
if (ok)
|
||||
JS_SET_RVAL(cx, vp, rval);
|
||||
JS_SET_RVAL(cx, vp, rval.value());
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::construct(JSContext *cx, JSObject *proxy,
|
||||
unsigned argc, Value *argv, Value *rval)
|
||||
IndirectProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
Value fval = GetConstruct(proxy);
|
||||
@ -355,44 +486,84 @@ ProxyHandler::construct(JSContext *cx, JSObject *proxy,
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
|
||||
IndirectProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp,
|
||||
Native native, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
ReportIncompatibleMethod(cx, args, clasp);
|
||||
return false;
|
||||
return CallJSNative(cx, native, args);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
|
||||
IndirectProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp,
|
||||
bool *bp)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
|
||||
JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
|
||||
return false;
|
||||
JSBool b;
|
||||
if (!JS_HasInstance(cx, GetProxyTargetObject(proxy), *vp, &b))
|
||||
return false;
|
||||
*bp = !!b;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSType
|
||||
ProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
|
||||
IndirectProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
|
||||
return TypeOfValue(cx, ObjectValue(*GetProxyTargetObject(proxy)));
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
|
||||
IndirectProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue,
|
||||
JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(OperationInProgress(cx, proxy));
|
||||
return false;
|
||||
return ObjectClassIs(*GetProxyTargetObject(proxy), classValue, cx);
|
||||
}
|
||||
|
||||
JSString *
|
||||
IndirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
return obj_toStringHelper(cx, GetProxyTargetObject(proxy));
|
||||
}
|
||||
|
||||
JSString *
|
||||
IndirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy,
|
||||
unsigned indent)
|
||||
{
|
||||
return fun_toStringHelper(cx, GetProxyTargetObject(proxy), indent);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
|
||||
RegExpGuard *g)
|
||||
{
|
||||
return RegExpToShared(cx, *GetProxyTargetObject(proxy), g);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
|
||||
Value *vp)
|
||||
{
|
||||
*vp = ObjectValue(*GetProxyTargetObject(proxy));
|
||||
if (hint == JSTYPE_VOID)
|
||||
return ToPrimitive(cx, vp);
|
||||
return ToPrimitive(cx, hint, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
IndirectProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
|
||||
{
|
||||
if (!js_IteratorMore(cx, RootedVarObject(cx, GetProxyTargetObject(proxy)),
|
||||
vp))
|
||||
return false;
|
||||
if (vp->toBoolean()) {
|
||||
*vp = cx->iterValue;
|
||||
cx->iterValue.setUndefined();
|
||||
} else
|
||||
vp->setMagic(JS_NO_ITER_VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
||||
IndirectProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
||||
{
|
||||
MarkSlot(trc, &proxy->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "targetObject");
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -521,7 +692,7 @@ ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
|
||||
}
|
||||
|
||||
/* Derived class for all scripted proxy handlers. */
|
||||
class ScriptedProxyHandler : public ProxyHandler {
|
||||
class ScriptedProxyHandler : public IndirectProxyHandler {
|
||||
public:
|
||||
ScriptedProxyHandler();
|
||||
virtual ~ScriptedProxyHandler();
|
||||
@ -546,12 +717,14 @@ class ScriptedProxyHandler : public ProxyHandler {
|
||||
virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp);
|
||||
|
||||
virtual JSType typeOf(JSContext *cx, JSObject *proxy);
|
||||
|
||||
static ScriptedProxyHandler singleton;
|
||||
};
|
||||
|
||||
static int sScriptedProxyHandlerFamily = 0;
|
||||
|
||||
ScriptedProxyHandler::ScriptedProxyHandler() : ProxyHandler(&sScriptedProxyHandlerFamily)
|
||||
ScriptedProxyHandler::ScriptedProxyHandler() : IndirectProxyHandler(&sScriptedProxyHandlerFamily)
|
||||
{
|
||||
}
|
||||
|
||||
@ -661,7 +834,7 @@ ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id, bool *bp)
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(has), fval.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(fval))
|
||||
return ProxyHandler::has(cx, proxy, id, bp);
|
||||
return BaseProxyHandler::has(cx, proxy, id, bp);
|
||||
return Trap1(cx, handler, fval, id, value.address()) &&
|
||||
ValueToBool(cx, value, bp);
|
||||
}
|
||||
@ -675,7 +848,7 @@ ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id, bool *bp)
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), fval.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(fval))
|
||||
return ProxyHandler::hasOwn(cx, proxy, id, bp);
|
||||
return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
|
||||
return Trap1(cx, handler, fval, id, value.address()) &&
|
||||
ValueToBool(cx, value, bp);
|
||||
}
|
||||
@ -695,7 +868,7 @@ ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy_, JSObject *receiver, j
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(get), fval.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(fval))
|
||||
return ProxyHandler::get(cx, proxy, receiver, id, vp);
|
||||
return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
|
||||
return Trap(cx, handler, fval, 2, argv, vp);
|
||||
}
|
||||
|
||||
@ -715,7 +888,7 @@ ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver, j
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(set), fval.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(fval))
|
||||
return ProxyHandler::set(cx, proxy, receiver, id, strict, vp);
|
||||
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
|
||||
return Trap(cx, handler, fval, 3, argv, value.address());
|
||||
}
|
||||
|
||||
@ -728,7 +901,7 @@ ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(keys), value.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(value))
|
||||
return ProxyHandler::keys(cx, proxy, props);
|
||||
return BaseProxyHandler::keys(cx, proxy, props);
|
||||
return Trap(cx, handler, value, 0, NULL, value.address()) &&
|
||||
ArrayToIdVector(cx, value, props);
|
||||
}
|
||||
@ -742,11 +915,22 @@ ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, V
|
||||
if (!GetDerivedTrap(cx, handler, ATOM(iterate), value.address()))
|
||||
return false;
|
||||
if (!js_IsCallable(value))
|
||||
return ProxyHandler::iterate(cx, proxy, flags, vp);
|
||||
return BaseProxyHandler::iterate(cx, proxy, flags, vp);
|
||||
return Trap(cx, handler, value, 0, NULL, vp) &&
|
||||
ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
|
||||
}
|
||||
|
||||
JSType
|
||||
ScriptedProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
/*
|
||||
* This function is only here to prevent a regression in
|
||||
* js1_8_5/extensions/scripted-proxies.js. It will be removed when the
|
||||
* direct proxy refactor is complete.
|
||||
*/
|
||||
return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
|
||||
}
|
||||
|
||||
ScriptedProxyHandler ScriptedProxyHandler::singleton;
|
||||
|
||||
class AutoPendingProxyOperation {
|
||||
@ -1487,7 +1671,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
|
||||
};
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv_, JSObject *proto_,
|
||||
js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, JSObject *proto_,
|
||||
JSObject *parent_, JSObject *call_, JSObject *construct_)
|
||||
{
|
||||
RootedVarValue priv(cx, priv_);
|
||||
|
@ -48,11 +48,11 @@
|
||||
namespace js {
|
||||
|
||||
/* Base class for all C++ proxy handlers. */
|
||||
class JS_FRIEND_API(ProxyHandler) {
|
||||
class JS_FRIEND_API(BaseProxyHandler) {
|
||||
void *mFamily;
|
||||
public:
|
||||
explicit ProxyHandler(void *family);
|
||||
virtual ~ProxyHandler();
|
||||
explicit BaseProxyHandler(void *family);
|
||||
virtual ~BaseProxyHandler();
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
||||
@ -100,6 +100,52 @@ class JS_FRIEND_API(ProxyHandler) {
|
||||
}
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
||||
public:
|
||||
explicit IndirectProxyHandler(void *family);
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool set,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
|
||||
jsid id, bool set,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool enumerate(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
||||
/* Derived traps are implemented in terms of fundamental traps */
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *proxy, Class *clasp,
|
||||
Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *proxy, const Value *vp,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual JSType typeOf(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE;
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue,
|
||||
JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE;
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *proxy,
|
||||
unsigned indent) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, JSObject *proxy,
|
||||
RegExpGuard *g) MOZ_OVERRIDE;
|
||||
virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool iteratorNext(JSContext *cx, JSObject *proxy,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual void trace(JSTracer *trc, JSObject *proxy) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
/* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
|
||||
class Proxy {
|
||||
public:
|
||||
@ -176,11 +222,11 @@ const uint32_t JSSLOT_PROXY_EXTRA = 2;
|
||||
const uint32_t JSSLOT_PROXY_CALL = 4;
|
||||
const uint32_t JSSLOT_PROXY_CONSTRUCT = 5;
|
||||
|
||||
inline ProxyHandler *
|
||||
inline BaseProxyHandler *
|
||||
GetProxyHandler(const JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(IsProxy(obj));
|
||||
return (ProxyHandler *) GetReservedSlot(obj, JSSLOT_PROXY_HANDLER).toPrivate();
|
||||
return (BaseProxyHandler *) GetReservedSlot(obj, JSSLOT_PROXY_HANDLER).toPrivate();
|
||||
}
|
||||
|
||||
inline const Value &
|
||||
@ -190,6 +236,13 @@ GetProxyPrivate(const JSObject *obj)
|
||||
return GetReservedSlot(obj, JSSLOT_PROXY_PRIVATE);
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
GetProxyTargetObject(const JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(IsProxy(obj));
|
||||
return GetProxyPrivate(obj).toObjectOrNull();
|
||||
}
|
||||
|
||||
inline const Value &
|
||||
GetProxyExtra(const JSObject *obj, size_t n)
|
||||
{
|
||||
@ -198,7 +251,7 @@ GetProxyExtra(const JSObject *obj, size_t n)
|
||||
}
|
||||
|
||||
inline void
|
||||
SetProxyHandler(JSObject *obj, ProxyHandler *handler)
|
||||
SetProxyHandler(JSObject *obj, BaseProxyHandler *handler)
|
||||
{
|
||||
JS_ASSERT(IsProxy(obj));
|
||||
SetReservedSlot(obj, JSSLOT_PROXY_HANDLER, PrivateValue(handler));
|
||||
@ -220,7 +273,7 @@ SetProxyExtra(JSObject *obj, size_t n, const Value &extra)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv,
|
||||
NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv,
|
||||
JSObject *proto, JSObject *parent,
|
||||
JSObject *call = NULL, JSObject *construct = NULL);
|
||||
|
||||
|
@ -182,7 +182,7 @@ struct TreeContext;
|
||||
class UpvarCookie;
|
||||
|
||||
class Proxy;
|
||||
class ProxyHandler;
|
||||
class BaseProxyHandler;
|
||||
class Wrapper;
|
||||
class CrossCompartmentWrapper;
|
||||
|
||||
|
@ -112,7 +112,7 @@ js::IsCrossCompartmentWrapper(const JSObject *wrapper)
|
||||
}
|
||||
|
||||
AbstractWrapper::AbstractWrapper(unsigned flags) :
|
||||
ProxyHandler(&sWrapperFamily),
|
||||
IndirectProxyHandler(&sWrapperFamily),
|
||||
mFlags(flags)
|
||||
{
|
||||
}
|
||||
@ -143,39 +143,22 @@ AbstractWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
desc->obj = NULL; // default result if we refuse to perform this action
|
||||
CHECKED(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc),
|
||||
CHECKED(IndirectProxyHandler::getPropertyDescriptor(cx, wrapper, id, set, desc),
|
||||
set ? SET : GET);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSPropertyDescriptor *desc)
|
||||
{
|
||||
// If obj is a proxy, we can do better than just guessing. This is
|
||||
// important for certain types of wrappers that wrap other wrappers.
|
||||
if (obj->isProxy())
|
||||
return Proxy::getOwnPropertyDescriptor(cx, obj, id, flags & JSRESOLVE_ASSIGNING, desc);
|
||||
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
|
||||
return false;
|
||||
if (desc->obj != obj)
|
||||
desc->obj = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AbstractWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
|
||||
PropertyDescriptor *desc)
|
||||
{
|
||||
desc->obj = NULL; // default result if we refuse to perform this action
|
||||
CHECKED(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc),
|
||||
set ? SET : GET);
|
||||
CHECKED(IndirectProxyHandler::getOwnPropertyDescriptor(cx, wrapper, id, set, desc), GET);
|
||||
}
|
||||
|
||||
bool
|
||||
AbstractWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
|
||||
{
|
||||
SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, desc->value,
|
||||
desc->getter, desc->setter, desc->attrs));
|
||||
SET(IndirectProxyHandler::defineProperty(cx, wrapper, id, desc));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -183,23 +166,14 @@ AbstractWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVec
|
||||
{
|
||||
// if we refuse to perform this action, props remains empty
|
||||
jsid id = JSID_VOID;
|
||||
GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, &props));
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueToBoolean(Value *vp, bool *bp)
|
||||
{
|
||||
*bp = js_ValueToBoolean(*vp);
|
||||
return true;
|
||||
GET(IndirectProxyHandler::getOwnPropertyNames(cx, wrapper, props));
|
||||
}
|
||||
|
||||
bool
|
||||
AbstractWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
*bp = true; // default result if we refuse to perform this action
|
||||
Value v;
|
||||
SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, &v) &&
|
||||
ValueToBoolean(&v, bp));
|
||||
SET(IndirectProxyHandler::delete_(cx, wrapper, id, bp));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -207,7 +181,7 @@ AbstractWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props
|
||||
{
|
||||
// if we refuse to perform this action, props remains empty
|
||||
static jsid id = JSID_VOID;
|
||||
GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, &props));
|
||||
GET(IndirectProxyHandler::enumerate(cx, wrapper, props));
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -271,7 +245,7 @@ Wrapper::call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp)
|
||||
{
|
||||
vp->setUndefined(); // default result if we refuse to perform this action
|
||||
const jsid id = JSID_VOID;
|
||||
CHECKED(ProxyHandler::call(cx, wrapper, argc, vp), CALL);
|
||||
CHECKED(IndirectProxyHandler::call(cx, wrapper, argc, vp), CALL);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -279,14 +253,14 @@ Wrapper::construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv,
|
||||
{
|
||||
vp->setUndefined(); // default result if we refuse to perform this action
|
||||
const jsid id = JSID_VOID;
|
||||
GET(ProxyHandler::construct(cx, wrapper, argc, argv, vp));
|
||||
GET(IndirectProxyHandler::construct(cx, wrapper, argc, argv, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args)
|
||||
{
|
||||
const jsid id = JSID_VOID;
|
||||
CHECKED(CallJSNative(cx, native, args), CALL);
|
||||
CHECKED(IndirectProxyHandler::nativeCall(cx, wrapper, clasp, native, args), CALL);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -294,20 +268,7 @@ Wrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp
|
||||
{
|
||||
*bp = false; // default result if we refuse to perform this action
|
||||
const jsid id = JSID_VOID;
|
||||
JSBool b = JS_FALSE;
|
||||
GET(JS_HasInstance(cx, wrappedObject(wrapper), *vp, &b) && Cond(b, bp));
|
||||
}
|
||||
|
||||
JSType
|
||||
Wrapper::typeOf(JSContext *cx, JSObject *wrapper)
|
||||
{
|
||||
return TypeOfValue(cx, ObjectValue(*wrappedObject(wrapper)));
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::objectClassIs(JSObject *wrapper, ESClassValue classValue, JSContext *cx)
|
||||
{
|
||||
return ObjectClassIs(*wrappedObject(wrapper), classValue, cx);
|
||||
GET(IndirectProxyHandler::hasInstance(cx, wrapper, vp, bp));
|
||||
}
|
||||
|
||||
JSString *
|
||||
@ -321,7 +282,7 @@ Wrapper::obj_toString(JSContext *cx, JSObject *wrapper)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
JSString *str = obj_toStringHelper(cx, wrappedObject(wrapper));
|
||||
JSString *str = IndirectProxyHandler::obj_toString(cx, wrapper);
|
||||
leave(cx, wrapper);
|
||||
return str;
|
||||
}
|
||||
@ -341,47 +302,11 @@ Wrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
JSString *str = ProxyHandler::fun_toString(cx, wrapper, indent);
|
||||
JSString *str = IndirectProxyHandler::fun_toString(cx, wrapper, indent);
|
||||
leave(cx, wrapper);
|
||||
return str;
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::regexp_toShared(JSContext *cx, JSObject *wrapper, RegExpGuard *g)
|
||||
{
|
||||
return RegExpToShared(cx, *wrappedObject(wrapper), g);
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp)
|
||||
{
|
||||
*vp = ObjectValue(*wrappedObject(wrapper));
|
||||
if (hint == JSTYPE_VOID)
|
||||
return ToPrimitive(cx, vp);
|
||||
return ToPrimitive(cx, hint, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
|
||||
{
|
||||
if (!js_IteratorMore(cx, RootedVarObject(cx, wrappedObject(wrapper)), vp))
|
||||
return false;
|
||||
|
||||
if (vp->toBoolean()) {
|
||||
*vp = cx->iterValue;
|
||||
cx->iterValue.setUndefined();
|
||||
} else {
|
||||
vp->setMagic(JS_NO_ITER_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Wrapper::trace(JSTracer *trc, JSObject *wrapper)
|
||||
{
|
||||
MarkSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
|
||||
}
|
||||
|
||||
JSObject *
|
||||
AbstractWrapper::wrappedObject(const JSObject *wrapper)
|
||||
{
|
||||
@ -877,7 +802,7 @@ CrossCompartmentWrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType h
|
||||
if (!call.enter())
|
||||
return false;
|
||||
|
||||
if (!Wrapper::defaultValue(cx, wrapper, hint, vp))
|
||||
if (!IndirectProxyHandler::defaultValue(cx, wrapper, hint, vp))
|
||||
return false;
|
||||
|
||||
call.leave();
|
||||
@ -889,7 +814,7 @@ CrossCompartmentWrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *v
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
NOTHING,
|
||||
Wrapper::iteratorNext(cx, wrapper, vp),
|
||||
IndirectProxyHandler::iteratorNext(cx, wrapper, vp),
|
||||
call.origin->wrap(cx, vp));
|
||||
}
|
||||
|
||||
@ -897,7 +822,7 @@ void
|
||||
CrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
|
||||
{
|
||||
MarkCrossCompartmentSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
|
||||
"wrappedObject");
|
||||
"targetObject");
|
||||
}
|
||||
|
||||
CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
|
||||
@ -943,7 +868,7 @@ SecurityWrapper<Base>::regexp_toShared(JSContext *cx, JSObject *obj, RegExpGuard
|
||||
template class js::SecurityWrapper<Wrapper>;
|
||||
template class js::SecurityWrapper<CrossCompartmentWrapper>;
|
||||
|
||||
class JS_FRIEND_API(DeadObjectProxy) : public ProxyHandler
|
||||
class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
||||
{
|
||||
private:
|
||||
static int sDeadObjectFamily;
|
||||
@ -981,7 +906,7 @@ class JS_FRIEND_API(DeadObjectProxy) : public ProxyHandler
|
||||
};
|
||||
|
||||
DeadObjectProxy::DeadObjectProxy()
|
||||
: ProxyHandler(&sDeadObjectFamily)
|
||||
: BaseProxyHandler(&sDeadObjectFamily)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class DummyFrameGuard;
|
||||
* want transparent forwarding behavior but don't want to use the derived
|
||||
* traps and other baggage of js::Wrapper.
|
||||
*/
|
||||
class JS_FRIEND_API(AbstractWrapper) : public ProxyHandler
|
||||
class JS_FRIEND_API(AbstractWrapper) : public IndirectProxyHandler
|
||||
{
|
||||
unsigned mFlags;
|
||||
public:
|
||||
@ -135,15 +135,8 @@ class JS_FRIEND_API(Wrapper) : public AbstractWrapper
|
||||
virtual bool construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) MOZ_OVERRIDE;
|
||||
virtual JSType typeOf(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE;
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g) MOZ_OVERRIDE;
|
||||
virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp) MOZ_OVERRIDE;
|
||||
|
||||
virtual void trace(JSTracer *trc, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
|
||||
using AbstractWrapper::Action;
|
||||
|
||||
@ -200,7 +193,6 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
|
||||
virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp);
|
||||
|
||||
virtual void trace(JSTracer *trc, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
|
||||
static CrossCompartmentWrapper singleton;
|
||||
|
@ -49,9 +49,9 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace binding {
|
||||
|
||||
class ProxyHandler : public js::ProxyHandler {
|
||||
class ProxyHandler : public js::BaseProxyHandler {
|
||||
protected:
|
||||
ProxyHandler() : js::ProxyHandler(ProxyFamily())
|
||||
ProxyHandler() : js::BaseProxyHandler(ProxyFamily())
|
||||
{
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ public:
|
||||
JSString *obj_toString(JSContext *cx, JSObject *proxy);
|
||||
void finalize(JSFreeOp *fop, JSObject *proxy);
|
||||
|
||||
static bool proxyHandlerIsList(js::ProxyHandler *handler) {
|
||||
static bool proxyHandlerIsList(js::BaseProxyHandler *handler) {
|
||||
return handler == &instance;
|
||||
}
|
||||
static bool objIsList(JSObject *obj) {
|
||||
|
@ -475,7 +475,7 @@ derivedClassTemplate = (
|
||||
"{\n"
|
||||
" if (!js::IsProxy(obj))\n"
|
||||
" return false;\n"
|
||||
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" js::BaseProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" return proxyHandlerIsList(handler) ||\n"
|
||||
"${checkproxyhandlers};\n"
|
||||
"}\n"
|
||||
@ -484,7 +484,7 @@ derivedClassTemplate = (
|
||||
"${nativeClass}*\n"
|
||||
"${name}Wrapper::getNative(JSObject *obj)\n"
|
||||
"{\n"
|
||||
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" js::BaseProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" if (proxyHandlerIsList(handler))\n"
|
||||
" return static_cast<${nativeClass}*>(js::GetProxyPrivate(obj).toPrivate());\n"
|
||||
"${castproxyhandlers}"
|
||||
|
@ -117,7 +117,7 @@ FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JSObject *wrapper, unsign
|
||||
// we don't know how to censor custom iterator objects. Instead we trigger
|
||||
// the default proxy iterate trap, which will ask enumerate() for the list
|
||||
// of (consored) ids.
|
||||
return js::ProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
|
@ -1336,7 +1336,7 @@ XrayWrapper<Base, Traits>::get(JSContext *cx, JSObject *wrapper, JSObject *recei
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
// NB: None of the functions we call are prepared for the receiver not
|
||||
// being the wrapper, so ignore the receiver here.
|
||||
return ProxyHandler::get(cx, wrapper, wrapper, id, vp);
|
||||
return BaseProxyHandler::get(cx, wrapper, wrapper, id, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
@ -1344,10 +1344,10 @@ bool
|
||||
XrayWrapper<Base, Traits>::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
|
||||
bool strict, js::Value *vp)
|
||||
{
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
// Skip our Base if it isn't already BaseProxyHandler.
|
||||
// NB: None of the functions we call are prepared for the receiver not
|
||||
// being the wrapper, so ignore the receiver here.
|
||||
return ProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
|
||||
return BaseProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
@ -1355,7 +1355,7 @@ bool
|
||||
XrayWrapper<Base, Traits>::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
return ProxyHandler::has(cx, wrapper, id, bp);
|
||||
return BaseProxyHandler::has(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
@ -1363,7 +1363,7 @@ bool
|
||||
XrayWrapper<Base, Traits>::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
return ProxyHandler::hasOwn(cx, wrapper, id, bp);
|
||||
return BaseProxyHandler::hasOwn(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
@ -1371,7 +1371,7 @@ bool
|
||||
XrayWrapper<Base, Traits>::keys(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props)
|
||||
{
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
return ProxyHandler::keys(cx, wrapper, props);
|
||||
return BaseProxyHandler::keys(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
@ -1380,7 +1380,7 @@ XrayWrapper<Base, Traits>::iterate(JSContext *cx, JSObject *wrapper, unsigned fl
|
||||
js::Value *vp)
|
||||
{
|
||||
// Skip our Base if it isn't already ProxyHandler.
|
||||
return ProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
return BaseProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
|
@ -7673,9 +7673,14 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsChangeHint aChange)
|
||||
{
|
||||
// We check GetStyleDisplay()->HasTransform() in addition to checking
|
||||
// IsTransformed() since we can get here for some frames that don't have the
|
||||
// NS_FRAME_MAY_BE_TRANSFORMED bit set (e.g. nsTableFrame; for a transformed
|
||||
// table that bit is only set on the nsTableOuterFrame).
|
||||
NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
|
||||
aFrame->IsTransformed() ||
|
||||
aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Only transform style should give a UpdateTransformLayer hint");
|
||||
"Unexpected UpdateTransformLayer hint");
|
||||
|
||||
nsIPresShell *shell = aPresContext->PresShell();
|
||||
if (shell->IsPaintingSuppressed()) {
|
||||
@ -7948,7 +7953,40 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
||||
ApplyRenderingChangeToTree(presContext, frame, hint);
|
||||
didInvalidate = true;
|
||||
}
|
||||
NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
|
||||
(hint & nsChangeHint_UpdateOverflow),
|
||||
"nsChangeHint_UpdateOverflow should be passed too");
|
||||
if ((hint & nsChangeHint_UpdateOverflow) && !didReflow) {
|
||||
if (hint & nsChangeHint_ChildrenOnlyTransform) {
|
||||
// When we process restyle events starting from the root of the frame
|
||||
// tree, we start at a ViewportFrame and traverse down the tree from
|
||||
// there. When we reach its nsHTMLScrollFrame child, that frame's
|
||||
// GetContent() returns the root element of the document, even though
|
||||
// that frame is not the root element's primary frame. The result of
|
||||
// this quirk is that we remove any pending change hints for the
|
||||
// root element and process them for the nsHTMLScrollFrame instead of
|
||||
// the root element's primary frame. For most change hints this is
|
||||
// not a problem, but for nsChangeHint_ChildrenOnlyTransform it is,
|
||||
// since the children that we want to call UpdateOverflow on are the
|
||||
// frames for the children of the root element, not the nsCanvasFrame
|
||||
// child of the nsHTMLScrollFrame. As a result we need to ignore
|
||||
// |frame| here and use frame->GetContent()->GetPrimaryFrame().
|
||||
nsIFrame *f = frame->GetContent()->GetPrimaryFrame();
|
||||
NS_ABORT_IF_FALSE(f->IsFrameOfType(nsIFrame::eSVG |
|
||||
nsIFrame::eSVGContainer),
|
||||
"Children-only transforms only expected on SVG frames");
|
||||
// Update overflow areas of children first:
|
||||
nsIFrame* childFrame = f->GetFirstPrincipalChild();
|
||||
for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
|
||||
NS_ABORT_IF_FALSE(childFrame->IsFrameOfType(nsIFrame::eSVG),
|
||||
"Not expecting non-SVG children");
|
||||
childFrame->UpdateOverflow();
|
||||
NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrSpecialSibling(childFrame),
|
||||
"SVG frames should not have continuations or special siblings");
|
||||
NS_ASSERTION(childFrame->GetParent() == frame,
|
||||
"SVG child frame not expected to have different parent");
|
||||
}
|
||||
}
|
||||
while (frame) {
|
||||
nsOverflowAreas* pre = static_cast<nsOverflowAreas*>
|
||||
(frame->Properties().Get(frame->PreTransformOverflowAreasProperty()));
|
||||
|
@ -113,7 +113,13 @@ enum nsChangeHint {
|
||||
* either through a change in its transform or a change in its position.
|
||||
* Does not update any descendant frames.
|
||||
*/
|
||||
nsChangeHint_UpdateOverflow = 0x800
|
||||
nsChangeHint_UpdateOverflow = 0x800,
|
||||
|
||||
/**
|
||||
* The children-only transform of an SVG frame changed, requiring the
|
||||
* overflow rects of the frame's immediate children to be updated.
|
||||
*/
|
||||
nsChangeHint_ChildrenOnlyTransform = 0x1000
|
||||
};
|
||||
|
||||
// Redefine these operators to return nothing. This will catch any use
|
||||
|
@ -2522,6 +2522,12 @@ nsRect
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
|
||||
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
// TODO: SVG needs to define what percentage translations resolve against.
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
return nsRect(nsPoint(0, 0), aFrame->GetSize());
|
||||
}
|
||||
|
||||
@ -2534,6 +2540,11 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
|
||||
nsRect result;
|
||||
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
// TODO: SVG needs to define what percentage translations resolve against.
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Iterate through the continuation list, unioning together all the
|
||||
* bounding rects.
|
||||
*/
|
||||
@ -2563,8 +2574,8 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
|
||||
const nsRect* aBoundsOverride)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Can't get a delta for an untransformed frame!");
|
||||
NS_PRECONDITION(aFrame->IsTransformed(),
|
||||
"Shouldn't get a delta for an untransformed frame!");
|
||||
|
||||
/* For both of the coordinates, if the value of -moz-transform is a
|
||||
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
||||
@ -2600,6 +2611,14 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
|
||||
*coords[index] =
|
||||
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
|
||||
}
|
||||
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
|
||||
coord.GetUnit() != eStyleUnit_Percent) {
|
||||
// <length> values represent offsets from the origin of the SVG element's
|
||||
// user space, not the top left of its bounds, so we must adjust for that:
|
||||
nscoord offset =
|
||||
(index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
|
||||
*coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
*coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
||||
@ -2620,8 +2639,8 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
|
||||
float aAppUnitsPerPixel)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Can't get a delta for an untransformed frame!");
|
||||
NS_PRECONDITION(aFrame->IsTransformed(),
|
||||
"Shouldn't get a delta for an untransformed frame!");
|
||||
NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
|
||||
"Can't get delta without a style parent!");
|
||||
|
||||
@ -2711,18 +2730,29 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
|
||||
/* Get the matrix, then change its basis to factor in the origin. */
|
||||
bool dummy;
|
||||
gfx3DMatrix result;
|
||||
// Call IsSVGTransformed() regardless of the value of
|
||||
// disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
|
||||
gfxMatrix svgTransform, transformFromSVGParent;
|
||||
bool hasSVGTransforms =
|
||||
aFrame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
|
||||
/* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
|
||||
if (disp->mSpecifiedTransform) {
|
||||
result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
|
||||
aFrame->GetStyleContext(),
|
||||
aFrame->PresContext(),
|
||||
dummy, bounds, aAppUnitsPerPixel);
|
||||
} else if (hasSVGTransforms) {
|
||||
result = gfx3DMatrix::From2D(svgTransform);
|
||||
} else {
|
||||
NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
|
||||
aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN,
|
||||
"If we don't have a transform, then we must have another reason to have an nsDisplayTransform created");
|
||||
}
|
||||
|
||||
if (hasSVGTransforms && !transformFromSVGParent.IsIdentity()) {
|
||||
result = result * gfx3DMatrix::From2D(transformFromSVGParent);
|
||||
}
|
||||
|
||||
const nsStyleDisplay* parentDisp = nsnull;
|
||||
nsStyleContext* parentStyleContext = aFrame->GetStyleContext()->GetParent();
|
||||
if (parentStyleContext) {
|
||||
|
@ -2340,8 +2340,8 @@ public:
|
||||
static nsRect GetFrameBoundsForTransform(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Given a frame with the -moz-transform property, returns the
|
||||
* transformation matrix for that frame.
|
||||
* Given a frame with the -moz-transform property or an SVG transform,
|
||||
* returns the transformation matrix for that frame.
|
||||
*
|
||||
* @param aFrame The frame to get the matrix from.
|
||||
* @param aOrigin Relative to which point this transform should be applied.
|
||||
|
@ -4606,6 +4606,22 @@ nsLayoutUtils::DeregisterImageRequest(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsLayoutUtils::PostRestyleEvent(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
{
|
||||
nsIDocument* doc = aElement->GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
|
||||
if (presShell) {
|
||||
presShell->FrameConstructor()->PostRestyleEvent(
|
||||
aElement, aRestyleHint, aMinChangeHint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
|
||||
const nsAString& aValue)
|
||||
: mContent(aContent),
|
||||
|
@ -55,6 +55,7 @@ class nsClientRectList;
|
||||
class nsFontFaceList;
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsStyleSet.h"
|
||||
@ -1652,6 +1653,15 @@ public:
|
||||
imgIRequest* aRequest,
|
||||
bool* aRequestRegistered);
|
||||
|
||||
/**
|
||||
* Shim to nsCSSFrameConstructor::PostRestyleEvent. Exists so that we
|
||||
* can avoid including nsCSSFrameConstructor.h and all its dependencies
|
||||
* in content files.
|
||||
*/
|
||||
static void PostRestyleEvent(mozilla::dom::Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint);
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Assert that there are no duplicate continuations of the same frame
|
||||
|
@ -155,6 +155,8 @@
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#endif
|
||||
#include "nsSMILAnimationController.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "SVGFragmentIdentifier.h"
|
||||
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
@ -2748,6 +2750,15 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const Element *root = mDocument->GetRootElement();
|
||||
if (root && root->IsSVG(nsGkAtoms::svg)) {
|
||||
// We need to execute this even if there is an empty anchor name
|
||||
// so that any existing SVG fragment identifier effect is removed
|
||||
if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument, aAnchorName)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Hold a reference to the ESM in case event dispatch tears us down.
|
||||
nsRefPtr<nsEventStateManager> esm = mPresContext->EventStateManager();
|
||||
|
||||
@ -2880,6 +2891,11 @@ PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll)
|
||||
fm->ClearFocus(focusedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
// If the target is an animation element, activate the animation
|
||||
if (content->IsNodeOfType(nsINode::eANIMATION)) {
|
||||
nsSVGUtils::ActivateByHyperlink(content.get());
|
||||
}
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
NS_NAMED_LITERAL_STRING(top, "top");
|
||||
|
@ -270,6 +270,8 @@ nsLayoutStatics::Initialize()
|
||||
|
||||
nsWindowMemoryReporter::Init();
|
||||
|
||||
nsSVGUtils::Init();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -961,7 +961,15 @@ bool
|
||||
nsIFrame::IsTransformed() const
|
||||
{
|
||||
return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
GetStyleDisplay()->HasTransform();
|
||||
(GetStyleDisplay()->HasTransform() ||
|
||||
IsSVGTransformed());
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::IsSVGTransformed(gfxMatrix *aOwnTransforms,
|
||||
gfxMatrix *aFromParentTransforms) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4643,9 +4651,11 @@ nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
|
||||
}
|
||||
}
|
||||
if (IsTransformed() && !rectIsTransformed) {
|
||||
nsRect newDamageRect;
|
||||
newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
|
||||
(aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
|
||||
nsRect newDamageRect = nsDisplayTransform::TransformRectOut
|
||||
(aDamageRect, this, nsPoint(-aX, -aY));
|
||||
if (!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
newDamageRect.UnionRect(newDamageRect, aDamageRect);
|
||||
}
|
||||
|
||||
// If we are preserving 3d, then our computed transform includes that of any
|
||||
// ancestor frames that also preserve 3d. Mark the rectangle as already being
|
||||
@ -4703,6 +4713,7 @@ nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
|
||||
gfx3DMatrix result =
|
||||
nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
|
||||
scaleFactor, nsnull, aOutAncestor);
|
||||
// XXXjwatt: seems like this will double count offsets in the face of preserve-3d:
|
||||
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
|
||||
/* Combine the raw transform with a translation to our parent. */
|
||||
result *= gfx3DMatrix::Translation
|
||||
@ -4835,6 +4846,21 @@ ComputeOutlineAndEffectsRect(nsIFrame* aFrame, bool* aAnyOutlineOrEffects,
|
||||
nsRect r = aOverflowRect;
|
||||
*aAnyOutlineOrEffects = false;
|
||||
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
// For SVG frames, we only need to account for filters.
|
||||
// TODO: We could also take account of clipPath and mask to reduce the
|
||||
// visual overflow, but that's not essential.
|
||||
if (aFrame->GetStyleSVGReset()->mFilter) {
|
||||
*aAnyOutlineOrEffects = true;
|
||||
if (aStoreRectProperties) {
|
||||
aFrame->Properties().
|
||||
Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
|
||||
}
|
||||
r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// box-shadow
|
||||
nsCSSShadowArray* boxShadows = aFrame->GetStyleBorder()->mBoxShadow;
|
||||
if (boxShadows) {
|
||||
@ -6741,10 +6767,13 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
// If the overflow area width or height is nscoord_MAX, then a
|
||||
// saturating union may have encounted an overflow, so the overflow may not
|
||||
// contain the frame border-box. Don't warn in that case.
|
||||
// Don't warn for SVG either, since SVG doesn't need the overflow area
|
||||
// to contain the frame bounds.
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
|
||||
NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
|
||||
r->width == nscoord_MAX || r->height == nscoord_MAX ||
|
||||
(mState & NS_FRAME_SVG_LAYOUT) ||
|
||||
r->Contains(nsRect(nsPoint(0,0), aNewSize)),
|
||||
"Computed overflow area must contain frame bounds");
|
||||
}
|
||||
@ -6763,10 +6792,13 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
}
|
||||
|
||||
// Overflow area must always include the frame's top-left and bottom-right,
|
||||
// even if the frame rect is empty.
|
||||
// even if the frame rect is empty (so we can scroll to those positions).
|
||||
// Pending a real fix for bug 426879, don't do this for inline frames
|
||||
// with zero width.
|
||||
if (aNewSize.width != 0 || !IsInlineFrame(this)) {
|
||||
// Do not do this for SVG either, since it will usually massively increase
|
||||
// the area unnecessarily.
|
||||
if ((aNewSize.width != 0 || !IsInlineFrame(this)) &&
|
||||
!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
nsRect& o = aOverflowAreas.Overflow(otype);
|
||||
o.UnionRectEdges(o, bounds);
|
||||
@ -6870,7 +6902,10 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
Invalidate(aOverflowAreas.VisualOverflow());
|
||||
}
|
||||
}
|
||||
if (anyOverflowChanged && hasTransform) {
|
||||
// XXXSDL For SVG the invalidation happens in UpdateBounds for now, so we
|
||||
// don't currently invalidate SVG here:
|
||||
if (anyOverflowChanged && hasTransform &&
|
||||
!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
// When there's a transform, changes to that style might require
|
||||
// repainting of the old and new overflow areas in the widget.
|
||||
// Repainting of the frame itself will not be required if there's
|
||||
|
@ -242,8 +242,9 @@ typedef PRUint64 nsFrameState;
|
||||
// more details.
|
||||
#define NS_FRAME_IS_SPECIAL NS_FRAME_STATE_BIT(15)
|
||||
|
||||
// If this bit is set, the frame may have a transform that it applies
|
||||
// to its coordinate system (e.g. CSS transform, SVG foreignObject).
|
||||
// If this bit is set, then transforms (e.g. CSS or SVG transforms) are allowed
|
||||
// to affect the frame, and a transform may currently be in affect. If this bit
|
||||
// is not set, then any transforms on the frame will be ignored.
|
||||
// This is used primarily in GetTransformMatrix to optimize for the
|
||||
// common case.
|
||||
#define NS_FRAME_MAY_BE_TRANSFORMED NS_FRAME_STATE_BIT(16)
|
||||
@ -311,6 +312,11 @@ typedef PRUint64 nsFrameState;
|
||||
// context?
|
||||
#define NS_FRAME_FONT_INFLATION_FLOW_ROOT NS_FRAME_STATE_BIT(42)
|
||||
|
||||
// This bit is set on SVG frames that are laid out using SVG's coordinate
|
||||
// system based layout (as opposed to any of the CSS layout models). Note that
|
||||
// this does not include nsSVGOuterSVGFrame since it takes part is CSS layout.
|
||||
#define NS_FRAME_SVG_LAYOUT NS_FRAME_STATE_BIT(43)
|
||||
|
||||
// Box layout bits
|
||||
#define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22)
|
||||
#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31)
|
||||
@ -1229,10 +1235,23 @@ public:
|
||||
virtual bool NeedsView() { return false; }
|
||||
|
||||
/**
|
||||
* Returns whether this frame has a transform matrix applied to it. This is true
|
||||
* if we have the -moz-transform property or if we're an SVGForeignObjectFrame.
|
||||
* Returns true if this frame is transformed (e.g. has CSS or SVG transforms)
|
||||
* or if its parent is an SVG frame that has children-only transforms (e.g.
|
||||
* an SVG viewBox attribute).
|
||||
*/
|
||||
virtual bool IsTransformed() const;
|
||||
bool IsTransformed() const;
|
||||
|
||||
/**
|
||||
* Returns true if this frame is an SVG frame that has SVG transforms applied
|
||||
* to it, or if its parent frame is an SVG frame that has children-only
|
||||
* transforms (e.g. an SVG viewBox attribute).
|
||||
* If aOwnTransforms is non-null and the frame has its own SVG transforms,
|
||||
* aOwnTransforms will be set to these transforms. If aFromParentTransforms
|
||||
* is non-null and the frame has an SVG parent with children-only transforms,
|
||||
* then aFromParentTransforms will be set to these transforms.
|
||||
*/
|
||||
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransforms = nsnull,
|
||||
gfxMatrix *aFromParentTransforms = nsnull) const;
|
||||
|
||||
/**
|
||||
* Returns whether this frame will attempt to preserve the 3d transforms of its
|
||||
@ -1969,8 +1988,8 @@ public:
|
||||
* @return A gfxMatrix that converts points in this frame's coordinate space
|
||||
* into points in aOutAncestor's coordinate space.
|
||||
*/
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aStopAtAncestor,
|
||||
nsIFrame **aOutAncestor);
|
||||
gfx3DMatrix GetTransformMatrix(nsIFrame* aStopAtAncestor,
|
||||
nsIFrame **aOutAncestor);
|
||||
|
||||
/**
|
||||
* Bit-flags to pass to IsFrameOfType()
|
||||
|
11
layout/reftests/svg/fragmentIdentifier-01.xhtml
Normal file
11
layout/reftests/svg/fragmentIdentifier-01.xhtml
Normal file
@ -0,0 +1,11 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Testcases for SVG fragment identifiers</title>
|
||||
</head>
|
||||
<body style="background-color: lime;">
|
||||
<div>
|
||||
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#limeView" />
|
||||
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100))" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/svg/fragmentIdentifier-rect-01.svg
Normal file
9
layout/reftests/svg/fragmentIdentifier-rect-01.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<view id="limeView" viewBox="0 200 100 100"/>
|
||||
|
||||
<rect fill="red" height="100%" width="100%"/>
|
||||
<rect fill="lime" x="0" y="200" height="100" width="100"/>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 270 B |
@ -111,6 +111,7 @@ random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == dynamic-text-04.svg dyna
|
||||
== dynamic-use-06.svg pass.svg
|
||||
random == dynamic-use-nested-01.svg dynamic-use-nested-01-ref.svg # bug 467498
|
||||
== dynamic-use-remove-width.svg dynamic-use-remove-width-ref.svg
|
||||
== fragmentIdentifier-01.xhtml pass.svg
|
||||
== linked-filter-01.svg pass.svg
|
||||
== linked-pattern-01.svg pass.svg
|
||||
== use-01.svg pass.svg
|
||||
|
@ -106,6 +106,7 @@ LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../../../xul/base/src \
|
||||
-I$(srcdir)/../../../../content/svg/content/src \
|
||||
-I$(srcdir)/../../../../content/base/src \
|
||||
-I$(srcdir)/../../../../content/smil \
|
||||
$(NULL)
|
||||
|
||||
libs::
|
||||
|
@ -110,7 +110,8 @@ public:
|
||||
enum SVGChangedFlags {
|
||||
DO_NOT_NOTIFY_RENDERING_OBSERVERS = 0x01,
|
||||
TRANSFORM_CHANGED = 0x02,
|
||||
COORD_CONTEXT_CHANGED = 0x04
|
||||
COORD_CONTEXT_CHANGED = 0x04,
|
||||
FULL_ZOOM_CHANGED = 0x08
|
||||
};
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags)=0;
|
||||
|
||||
@ -140,9 +141,6 @@ public:
|
||||
|
||||
// Are we a container frame?
|
||||
NS_IMETHOD_(bool) IsDisplayContainer()=0;
|
||||
|
||||
// Does this frame have an current covered region in mRect (aka GetRect())?
|
||||
NS_IMETHOD_(bool) HasValidCoveredRect()=0;
|
||||
};
|
||||
|
||||
#endif // __NS_ISVGCHILDFRAME_H__
|
||||
|
@ -38,8 +38,12 @@
|
||||
#include "nsSVGContainerFrame.h"
|
||||
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "SVGAnimatedTransformList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsSVGContainerFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsSVGContainerFrame)
|
||||
@ -96,6 +100,17 @@ nsSVGContainerFrame::RemoveFrame(ChildListID aListID,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGContainerFrame::UpdateOverflow()
|
||||
{
|
||||
if (mState & NS_STATE_SVG_NONDISPLAY_CHILD) {
|
||||
// We don't maintain overflow rects.
|
||||
// XXX It would have be better if the restyle request hadn't even happened.
|
||||
return false;
|
||||
}
|
||||
return nsSVGContainerFrameBase::UpdateOverflow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
@ -163,6 +178,32 @@ nsSVGDisplayContainerFrame::RemoveFrame(ChildListID aListID,
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGDisplayContainerFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
|
||||
gfxMatrix *aFromParentTransform) const
|
||||
{
|
||||
bool foundTransform = false;
|
||||
|
||||
// Check if our parent has children-only transforms:
|
||||
nsIFrame *parent = GetParent();
|
||||
if (parent &&
|
||||
parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
|
||||
foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
|
||||
HasChildrenOnlyTransform(aFromParentTransform);
|
||||
}
|
||||
|
||||
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
|
||||
const SVGAnimatedTransformList *list = content->GetAnimatedTransformList();
|
||||
if (list && !list->GetAnimValue().IsEmpty()) {
|
||||
if (aOwnTransform) {
|
||||
*aOwnTransform = content->PrependLocalTransformsTo(gfxMatrix(),
|
||||
nsSVGElement::eUserSpaceToParent);
|
||||
}
|
||||
foundTransform = true;
|
||||
}
|
||||
return foundTransform;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGChildFrame methods
|
||||
|
||||
@ -203,6 +244,9 @@ nsSVGDisplayContainerFrame::UpdateBounds()
|
||||
NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
|
||||
"UpdateBounds mechanism not designed for this");
|
||||
|
||||
NS_ABORT_IF_FALSE(GetType() != nsGkAtoms::svgOuterSVGFrame,
|
||||
"Do not call on outer-<svg>");
|
||||
|
||||
if (!nsSVGUtils::NeedsUpdatedBounds(this)) {
|
||||
return;
|
||||
}
|
||||
@ -221,6 +265,8 @@ nsSVGDisplayContainerFrame::UpdateBounds()
|
||||
mState &= ~NS_FRAME_FIRST_REFLOW; // tell our children
|
||||
}
|
||||
|
||||
nsOverflowAreas overflowRects;
|
||||
|
||||
for (nsIFrame* kid = mFrames.FirstChild(); kid;
|
||||
kid = kid->GetNextSibling()) {
|
||||
nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
|
||||
@ -228,14 +274,43 @@ nsSVGDisplayContainerFrame::UpdateBounds()
|
||||
NS_ABORT_IF_FALSE(!(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
|
||||
"Check for this explicitly in the |if|, then");
|
||||
SVGFrame->UpdateBounds();
|
||||
|
||||
// We build up our child frame overflows here instead of using
|
||||
// nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same
|
||||
// frame list, and we're iterating over that list now anyway.
|
||||
ConsiderChildOverflow(overflowRects, kid);
|
||||
}
|
||||
}
|
||||
|
||||
// <svg> can create an SVG viewport with an offset due to its
|
||||
// x/y/width/height attributes, and <use> can introduce an offset with an
|
||||
// empty mRect (any width/height is copied to an anonymous <svg> child).
|
||||
// Other than that containers should not set mRect since all other offsets
|
||||
// come from transforms, which are accounted for by nsDisplayTransform.
|
||||
// Note that we rely on |overflow:visible| to allow display list items to be
|
||||
// created for our children.
|
||||
NS_ABORT_IF_FALSE(mContent->Tag() == nsGkAtoms::svg ||
|
||||
(mContent->Tag() == nsGkAtoms::use &&
|
||||
mRect.Size() == nsSize(0,0)) ||
|
||||
mRect.IsEqualEdges(nsRect()),
|
||||
"Only inner-<svg>/<use> is expected to have mRect set");
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
// Make sure we have our filter property (if any) before calling
|
||||
// FinishAndStoreOverflow (subsequent filter changes are handled off
|
||||
// nsChangeHint_UpdateEffects):
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
FinishAndStoreOverflow(overflowRects, mRect.Size());
|
||||
|
||||
// Remove state bits after FinishAndStoreOverflow so that it doesn't
|
||||
// invalidate on first reflow:
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
// XXXsvgreflow once we store bounds on containers, do...
|
||||
// nsSVGUtils::InvalidateBounds(this);
|
||||
// XXXSDL Make Invalidate() call nsSVGUtils::InvalidateBounds(this)
|
||||
// so that we invalidate under FinishAndStoreOverflow().
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -68,8 +68,11 @@ class nsSVGContainerFrame : public nsSVGContainerFrameBase
|
||||
friend nsIFrame* NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
protected:
|
||||
nsSVGContainerFrame(nsStyleContext* aContext) :
|
||||
nsSVGContainerFrameBase(aContext) {}
|
||||
nsSVGContainerFrame(nsStyleContext* aContext)
|
||||
: nsSVGContainerFrameBase(aContext)
|
||||
{
|
||||
AddStateBits(NS_FRAME_SVG_LAYOUT);
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsSVGContainerFrame)
|
||||
@ -79,6 +82,17 @@ public:
|
||||
// Returns the transform to our gfxContext (to device pixels, not CSS px)
|
||||
virtual gfxMatrix GetCanvasTM() { return gfxMatrix(); }
|
||||
|
||||
/**
|
||||
* Returns true if the frame's content has a transform that applies only to
|
||||
* its children, and not to the frame itself. For example, an implicit
|
||||
* transform introduced by a 'viewBox' attribute, or an explicit transform
|
||||
* due to a root-<svg> having its currentScale/currentTransform properties
|
||||
* set. If aTransform is non-null, then it will be set to the transform.
|
||||
*/
|
||||
virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// nsIFrame:
|
||||
NS_IMETHOD AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList);
|
||||
@ -93,6 +107,8 @@ public:
|
||||
return nsSVGContainerFrameBase::IsFrameOfType(
|
||||
aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
|
||||
}
|
||||
|
||||
virtual bool UpdateOverflow();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -103,8 +119,11 @@ class nsSVGDisplayContainerFrame : public nsSVGContainerFrame,
|
||||
public nsISVGChildFrame
|
||||
{
|
||||
protected:
|
||||
nsSVGDisplayContainerFrame(nsStyleContext* aContext) :
|
||||
nsSVGContainerFrame(aContext) {}
|
||||
nsSVGDisplayContainerFrame(nsStyleContext* aContext)
|
||||
: nsSVGContainerFrame(aContext)
|
||||
{
|
||||
AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsSVGDisplayContainerFrame)
|
||||
@ -121,6 +140,9 @@ public:
|
||||
nsIFrame* aParent,
|
||||
nsIFrame* aPrevInFlow);
|
||||
|
||||
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform = nsnull,
|
||||
gfxMatrix *aFromParentTransform = nsnull) const;
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
NS_IMETHOD PaintSVG(nsRenderingContext* aContext,
|
||||
const nsIntRect *aDirtyRect);
|
||||
@ -131,7 +153,6 @@ public:
|
||||
virtual SVGBBox GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
PRUint32 aFlags);
|
||||
NS_IMETHOD_(bool) IsDisplayContainer() { return true; }
|
||||
NS_IMETHOD_(bool) HasValidCoveredRect() { return false; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -99,7 +99,8 @@ public:
|
||||
nsSVGFilterPaintCallback *aPaint,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
const nsIntRect *aOverrideSourceBBox);
|
||||
const nsIntRect *aOverrideSourceBBox,
|
||||
const gfxMatrix *aOverrideUserToDeviceSpace = nsnull);
|
||||
~nsAutoFilterInstance() {}
|
||||
|
||||
// If this returns null, then draw nothing. Either the filter draws
|
||||
@ -115,7 +116,8 @@ nsAutoFilterInstance::nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
nsSVGFilterPaintCallback *aPaint,
|
||||
const nsIntRect *aDirtyOutputRect,
|
||||
const nsIntRect *aDirtyInputRect,
|
||||
const nsIntRect *aOverrideSourceBBox)
|
||||
const nsIntRect *aOverrideSourceBBox,
|
||||
const gfxMatrix *aOverrideUserToDeviceSpace)
|
||||
{
|
||||
const nsSVGFilterElement *filter = aFilterFrame->GetFilterContent();
|
||||
|
||||
@ -161,10 +163,11 @@ nsAutoFilterInstance::nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
return;
|
||||
}
|
||||
|
||||
gfxMatrix userToDeviceSpace = nsSVGUtils::GetCanvasTM(aTarget);
|
||||
if (userToDeviceSpace.IsSingular()) {
|
||||
// nothing to draw
|
||||
return;
|
||||
gfxMatrix userToDeviceSpace;
|
||||
if (aOverrideUserToDeviceSpace) {
|
||||
userToDeviceSpace = *aOverrideUserToDeviceSpace;
|
||||
} else {
|
||||
userToDeviceSpace = nsSVGUtils::GetCanvasTM(aTarget);
|
||||
}
|
||||
|
||||
// Calculate filterRes (the width and height of the pixel buffer of the
|
||||
@ -195,7 +198,12 @@ nsAutoFilterInstance::nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
} else {
|
||||
// Match filterRes as closely as possible to the pixel density of the nearest
|
||||
// outer 'svg' device space:
|
||||
float scale = nsSVGUtils::MaxExpansion(userToDeviceSpace);
|
||||
gfxMatrix canvasTM = nsSVGUtils::GetCanvasTM(aTarget);
|
||||
if (canvasTM.IsSingular()) {
|
||||
// nothing to draw
|
||||
return;
|
||||
}
|
||||
float scale = nsSVGUtils::MaxExpansion(canvasTM);
|
||||
|
||||
filterRegion.Scale(scale);
|
||||
filterRegion.RoundOut();
|
||||
@ -228,8 +236,20 @@ nsAutoFilterInstance::nsAutoFilterInstance(nsIFrame *aTarget,
|
||||
nsIntRect targetBoundsDeviceSpace;
|
||||
nsISVGChildFrame* svgTarget = do_QueryFrame(aTarget);
|
||||
if (svgTarget) {
|
||||
targetBoundsDeviceSpace.UnionRect(targetBoundsDeviceSpace,
|
||||
svgTarget->GetCoveredRegion().ToOutsidePixels(aTarget->PresContext()->AppUnitsPerDevPixel()));
|
||||
if (aOverrideUserToDeviceSpace) {
|
||||
// If aOverrideUserToDeviceSpace is specified, it is a simple
|
||||
// CSS-px-to-dev-px transform passed by nsSVGFilterFrame::GetFilterBBox()
|
||||
// when requesting the filter expansion of the overflow rects in frame
|
||||
// space. In this case GetCoveredRegion() is not what we want since it is
|
||||
// in outer-<svg> space, GetFilterBBox passes in the pre-filter bounds of
|
||||
// the frame in frame space for us to use instead.
|
||||
NS_ASSERTION(aDirtyInputRect, "Who passed aOverrideUserToDeviceSpace?");
|
||||
targetBoundsDeviceSpace = *aDirtyInputRect;
|
||||
} else {
|
||||
targetBoundsDeviceSpace =
|
||||
svgTarget->GetCoveredRegion().ToOutsidePixels(aTarget->
|
||||
PresContext()->AppUnitsPerDevPixel());
|
||||
}
|
||||
}
|
||||
nsIntRect targetBoundsFilterSpace =
|
||||
MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, &targetBoundsDeviceSpace);
|
||||
@ -471,9 +491,27 @@ nsSVGFilterFrame::GetSourceForInvalidArea(nsIFrame *aTarget, const nsIntRect& aR
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
nsSVGFilterFrame::GetFilterBBox(nsIFrame *aTarget, const nsIntRect *aSourceBBox)
|
||||
nsSVGFilterFrame::GetFilterBBox(nsIFrame *aTarget,
|
||||
const nsIntRect *aOverrideBBox,
|
||||
const nsIntRect *aPreFilterBounds)
|
||||
{
|
||||
nsAutoFilterInstance instance(aTarget, this, nsnull, nsnull, nsnull, aSourceBBox);
|
||||
bool overrideCTM = false;
|
||||
gfxMatrix ctm;
|
||||
|
||||
if (aTarget->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
// For most filter operations on SVG frames we want information in
|
||||
// outer-<svg> device space, but in this case we want the visual overflow
|
||||
// rect relative to aTarget itself. For that we need to prevent the filter
|
||||
// code using GetCanvasTM().
|
||||
overrideCTM = true;
|
||||
PRInt32 appUnitsPerDevPixel = aTarget->PresContext()->AppUnitsPerDevPixel();
|
||||
float devPxPerCSSPx =
|
||||
1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
|
||||
ctm.Scale(devPxPerCSSPx, devPxPerCSSPx);
|
||||
}
|
||||
|
||||
nsAutoFilterInstance instance(aTarget, this, nsnull, nsnull, aPreFilterBounds,
|
||||
aOverrideBBox, overrideCTM ? &ctm : nsnull);
|
||||
if (!instance.get())
|
||||
return nsIntRect();
|
||||
|
||||
|
@ -99,9 +99,11 @@ public:
|
||||
* Returns the bounding box of the post-filter area of aTarget.
|
||||
* The rectangles are relative to the origin of the outer svg, if aTarget is SVG,
|
||||
* relative to aTarget itself otherwise, in device pixels.
|
||||
* @param aSourceBBox overrides the normal bbox for the source, if non-null
|
||||
* @param aOverrideBBox overrides the normal bbox for the source, if non-null
|
||||
*/
|
||||
nsIntRect GetFilterBBox(nsIFrame *aTarget, const nsIntRect *aSourceBBox);
|
||||
nsIntRect GetFilterBBox(nsIFrame *aTarget,
|
||||
const nsIntRect *aOverrideBBox = nsnull,
|
||||
const nsIntRect *aPreFilterBounds = nsnull);
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD Init(nsIContent* aContent,
|
||||
|
@ -73,7 +73,8 @@ nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
|
||||
: nsSVGForeignObjectFrameBase(aContext),
|
||||
mInReflow(false)
|
||||
{
|
||||
AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED);
|
||||
AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
|
||||
NS_FRAME_SVG_LAYOUT);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -305,24 +306,6 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
|
||||
return rv;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame* aAncestor,
|
||||
nsIFrame **aOutAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
|
||||
|
||||
/* Set the ancestor to be the outer frame. */
|
||||
*aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this);
|
||||
NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?");
|
||||
|
||||
if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
|
||||
return gfx3DMatrix::From2D(gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
/* Return the matrix back to the root, factoring in the x and y offsets. */
|
||||
return gfx3DMatrix::From2D(GetCanvasTMForChildren());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIFrame*)
|
||||
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
|
||||
{
|
||||
@ -415,6 +398,19 @@ nsSVGForeignObjectFrame::UpdateBounds()
|
||||
|
||||
DoReflow();
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
// Make sure we have our filter property (if any) before calling
|
||||
// FinishAndStoreOverflow (subsequent filter changes are handled off
|
||||
// nsChangeHint_UpdateEffects):
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
// TODO: once we support |overflow:visible| on foreignObject, then we will
|
||||
// need to take account of our descendants here.
|
||||
nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
|
||||
nsOverflowAreas overflowAreas(overflow, overflow);
|
||||
FinishAndStoreOverflow(overflowAreas, mRect.Size());
|
||||
|
||||
// Now unset the various reflow bits:
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
@ -423,6 +419,7 @@ nsSVGForeignObjectFrame::UpdateBounds()
|
||||
// We only invalidate if our outer-<svg> has already had its
|
||||
// initial reflow (since if it hasn't, its entire area will be
|
||||
// invalidated when it gets that initial reflow):
|
||||
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||
nsSVGUtils::InvalidateBounds(this, true);
|
||||
}
|
||||
}
|
||||
|
@ -81,20 +81,6 @@ public:
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/**
|
||||
* Foreign objects are always transformed.
|
||||
*/
|
||||
virtual bool IsTransformed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Foreign objects can return a transform matrix.
|
||||
*/
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aAncestor,
|
||||
nsIFrame **aOutAncestor);
|
||||
|
||||
/**
|
||||
* Get the "type" of the frame
|
||||
*
|
||||
@ -129,9 +115,6 @@ public:
|
||||
virtual SVGBBox GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
PRUint32 aFlags);
|
||||
NS_IMETHOD_(bool) IsDisplayContainer() { return true; }
|
||||
NS_IMETHOD_(bool) HasValidCoveredRect() {
|
||||
return !(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
}
|
||||
|
||||
gfxMatrix GetCanvasTM();
|
||||
|
||||
|
@ -69,7 +69,11 @@ class nsSVGGeometryFrame : public nsSVGGeometryFrameBase
|
||||
protected:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
nsSVGGeometryFrame(nsStyleContext *aContext) : nsSVGGeometryFrameBase(aContext) {}
|
||||
nsSVGGeometryFrame(nsStyleContext *aContext)
|
||||
: nsSVGGeometryFrameBase(aContext)
|
||||
{
|
||||
AddStateBits(NS_FRAME_SVG_LAYOUT);
|
||||
}
|
||||
|
||||
public:
|
||||
// nsIFrame interface:
|
||||
|
@ -512,6 +512,10 @@ nsSVGGlyphFrame::UpdateBounds()
|
||||
mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG(
|
||||
mRect, GetCanvasTM(), PresContext());
|
||||
|
||||
nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
|
||||
nsOverflowAreas overflowAreas(overflow, overflow);
|
||||
FinishAndStoreOverflow(overflowAreas, mRect.Size());
|
||||
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
@ -519,6 +523,7 @@ nsSVGGlyphFrame::UpdateBounds()
|
||||
// We only invalidate if our outer-<svg> has already had its
|
||||
// initial reflow (since if it hasn't, its entire area will be
|
||||
// invalidated when it gets that initial reflow):
|
||||
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||
nsSVGUtils::InvalidateBounds(this, true);
|
||||
}
|
||||
}
|
||||
|
@ -185,9 +185,6 @@ public:
|
||||
virtual void UpdateBounds();
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD_(bool) IsDisplayContainer() { return false; }
|
||||
NS_IMETHOD_(bool) HasValidCoveredRect() {
|
||||
return !(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
}
|
||||
|
||||
// nsSVGGeometryFrame methods
|
||||
gfxMatrix GetCanvasTM();
|
||||
|
@ -514,6 +514,17 @@ nsSVGImageFrame::UpdateBounds()
|
||||
mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG(
|
||||
mRect, GetCanvasTM(), PresContext());
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
// Make sure we have our filter property (if any) before calling
|
||||
// FinishAndStoreOverflow (subsequent filter changes are handled off
|
||||
// nsChangeHint_UpdateEffects):
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
|
||||
nsOverflowAreas overflowAreas(overflow, overflow);
|
||||
FinishAndStoreOverflow(overflowAreas, mRect.Size());
|
||||
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
@ -521,6 +532,7 @@ nsSVGImageFrame::UpdateBounds()
|
||||
// We only invalidate if our outer-<svg> has already had its
|
||||
// initial reflow (since if it hasn't, its entire area will be
|
||||
// invalidated when it gets that initial reflow):
|
||||
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||
nsSVGUtils::InvalidateBounds(this, true);
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,20 @@ nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
|
||||
return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aDirtyRect);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGInnerSVGFrame::UpdateBounds()
|
||||
{
|
||||
// mRect must be set before FinishAndStoreOverflow is called in order
|
||||
// for our overflow areas to be clipped correctly.
|
||||
float x, y, width, height;
|
||||
static_cast<nsSVGSVGElement*>(mContent)->
|
||||
GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
|
||||
mRect = nsLayoutUtils::RoundGfxRectToAppRect(
|
||||
gfxRect(x, y, width, height),
|
||||
PresContext()->AppUnitsPerCSSPixel());
|
||||
nsSVGInnerSVGFrameBase::UpdateBounds();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGInnerSVGFrame::NotifySVGChanged(PRUint32 aFlags)
|
||||
{
|
||||
@ -171,24 +185,21 @@ nsSVGInnerSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
PRInt32 aModType)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
|
||||
nsSVGSVGElement* content = static_cast<nsSVGSVGElement*>(mContent);
|
||||
|
||||
if (aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height) {
|
||||
|
||||
nsSVGSVGElement* svg = static_cast<nsSVGSVGElement*>(mContent);
|
||||
if (svg->HasViewBox()) {
|
||||
|
||||
if (content->HasViewBoxOrSyntheticViewBox()) {
|
||||
// make sure our cached transform matrix gets (lazily) updated
|
||||
mCanvasTM = nsnull;
|
||||
|
||||
content->ChildrenOnlyTransformChanged();
|
||||
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
|
||||
} else {
|
||||
|
||||
PRUint32 flags = COORD_CONTEXT_CHANGED;
|
||||
|
||||
if (mCanvasTM && mCanvasTM->IsSingular()) {
|
||||
|
||||
mCanvasTM = nsnull;
|
||||
|
||||
flags |= TRANSFORM_CHANGED;
|
||||
}
|
||||
nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
|
||||
@ -205,6 +216,12 @@ nsSVGInnerSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsSVGUtils::NotifyChildrenOfSVGChange(
|
||||
this, aAttribute == nsGkAtoms::viewBox ?
|
||||
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
||||
|
||||
if (aAttribute == nsGkAtoms::viewBox ||
|
||||
(aAttribute == nsGkAtoms::preserveAspectRatio &&
|
||||
content->HasViewBoxOrSyntheticViewBox())) {
|
||||
content->ChildrenOnlyTransformChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,3 +282,17 @@ nsSVGInnerSVGFrame::GetCanvasTM()
|
||||
return *mCanvasTM;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGInnerSVGFrame::HasChildrenOnlyTransform(gfxMatrix *aTransform) const
|
||||
{
|
||||
nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
|
||||
|
||||
if (content->HasViewBoxOrSyntheticViewBox()) {
|
||||
// XXX Maybe return false if the transform is the identity transform?
|
||||
if (aTransform) {
|
||||
*aTransform = content->GetViewBoxTransform();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -84,12 +84,15 @@ public:
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
NS_IMETHOD PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect);
|
||||
virtual void UpdateBounds();
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
|
||||
|
||||
// nsSVGContainerFrame methods:
|
||||
virtual gfxMatrix GetCanvasTM();
|
||||
|
||||
virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const;
|
||||
|
||||
// nsISVGSVGFrame interface:
|
||||
virtual void NotifyViewportOrTransformChanged(PRUint32 aFlags);
|
||||
|
||||
|
@ -146,6 +146,8 @@ nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
|
||||
#endif
|
||||
, mIsRootContent(false)
|
||||
{
|
||||
// Outer-<svg> has CSS layout, so remove this bit:
|
||||
RemoveStateBits(NS_FRAME_SVG_LAYOUT);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -416,7 +418,7 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
|
||||
svgElem->SetViewportSize(newViewportSize);
|
||||
}
|
||||
if (mFullZoom != PresContext()->GetFullZoom()) {
|
||||
changeBits |= TRANSFORM_CHANGED;
|
||||
changeBits |= FULL_ZOOM_CHANGED;
|
||||
mFullZoom = PresContext()->GetFullZoom();
|
||||
}
|
||||
mViewportInitialized = true;
|
||||
@ -617,9 +619,14 @@ nsSVGOuterSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
this, aAttribute == nsGkAtoms::viewBox ?
|
||||
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
||||
|
||||
static_cast<nsSVGSVGElement*>(mContent)->ChildrenOnlyTransformChanged();
|
||||
|
||||
} else if (aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height) {
|
||||
|
||||
// Don't call ChildrenOnlyTransformChanged() here, since we call it
|
||||
// under Reflow if the width/height actually changed.
|
||||
|
||||
nsIFrame* embeddingFrame;
|
||||
if (IsRootOfReplacedElementSubDoc(&embeddingFrame) && embeddingFrame) {
|
||||
if (DependsOnIntrinsicSize(embeddingFrame)) {
|
||||
@ -703,7 +710,8 @@ void
|
||||
nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(PRUint32 aFlags)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aFlags &&
|
||||
!(aFlags & ~(COORD_CONTEXT_CHANGED | TRANSFORM_CHANGED)),
|
||||
!(aFlags & ~(COORD_CONTEXT_CHANGED | TRANSFORM_CHANGED |
|
||||
FULL_ZOOM_CHANGED)),
|
||||
"Unexpected aFlags value");
|
||||
|
||||
// No point in doing anything when were not init'ed yet:
|
||||
@ -729,9 +737,21 @@ nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(PRUint32 aFlags)
|
||||
}
|
||||
}
|
||||
|
||||
bool haveNonFulLZoomTransformChange = (aFlags & TRANSFORM_CHANGED);
|
||||
|
||||
if (aFlags & FULL_ZOOM_CHANGED) {
|
||||
// Convert FULL_ZOOM_CHANGED to TRANSFORM_CHANGED:
|
||||
aFlags = (aFlags & ~FULL_ZOOM_CHANGED) | TRANSFORM_CHANGED;
|
||||
}
|
||||
|
||||
if (aFlags & TRANSFORM_CHANGED) {
|
||||
// Make sure our canvas transform matrix gets (lazily) recalculated:
|
||||
mCanvasTM = nsnull;
|
||||
|
||||
if (haveNonFulLZoomTransformChange &&
|
||||
!(mState & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
||||
content->ChildrenOnlyTransformChanged();
|
||||
}
|
||||
}
|
||||
|
||||
nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags);
|
||||
@ -750,21 +770,31 @@ nsSVGOuterSVGFrame::GetCanvasTM()
|
||||
1.0f / PresContext()->AppUnitsToFloatCSSPixels(
|
||||
PresContext()->AppUnitsPerDevPixel());
|
||||
|
||||
gfxMatrix viewBoxTM = content->GetViewBoxTransform();
|
||||
|
||||
gfxMatrix zoomPanTM;
|
||||
if (mIsRootContent) {
|
||||
const nsSVGTranslatePoint& translate = content->GetCurrentTranslate();
|
||||
zoomPanTM.Translate(gfxPoint(translate.GetX(), translate.GetY()));
|
||||
zoomPanTM.Scale(content->GetCurrentScale(), content->GetCurrentScale());
|
||||
}
|
||||
|
||||
gfxMatrix TM = viewBoxTM * zoomPanTM * gfxMatrix().Scale(devPxPerCSSPx, devPxPerCSSPx);
|
||||
mCanvasTM = new gfxMatrix(TM);
|
||||
gfxMatrix tm = content->PrependLocalTransformsTo(
|
||||
gfxMatrix().Scale(devPxPerCSSPx, devPxPerCSSPx));
|
||||
mCanvasTM = new gfxMatrix(tm);
|
||||
}
|
||||
return *mCanvasTM;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGOuterSVGFrame::HasChildrenOnlyTransform(gfxMatrix *aTransform) const
|
||||
{
|
||||
nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
|
||||
|
||||
bool hasTransform = content->HasChildrenOnlyTransform();
|
||||
|
||||
if (hasTransform && aTransform) {
|
||||
// Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
|
||||
gfxMatrix identity;
|
||||
*aTransform =
|
||||
content->PrependLocalTransformsTo(identity,
|
||||
nsSVGElement::eChildToUserSpace);
|
||||
}
|
||||
|
||||
return hasTransform;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation helpers
|
||||
|
||||
|
@ -113,12 +113,21 @@ public:
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
|
||||
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
|
||||
gfxMatrix *aFromParentTransform) const {
|
||||
// Outer-<svg> can transform its children with viewBox, currentScale and
|
||||
// currentTranslate, but it itself is not transformed by SVG transforms.
|
||||
return false;
|
||||
}
|
||||
|
||||
// nsISVGSVGFrame interface:
|
||||
virtual void NotifyViewportOrTransformChanged(PRUint32 aFlags);
|
||||
|
||||
// nsSVGContainerFrame methods:
|
||||
virtual gfxMatrix GetCanvasTM();
|
||||
|
||||
virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
bool BitmapFallbackEnabled() const {
|
||||
return mEnableBitmapFallback;
|
||||
|
@ -49,6 +49,9 @@
|
||||
#include "nsSVGMarkerFrame.h"
|
||||
#include "nsSVGPathGeometryElement.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "SVGAnimatedTransformList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
@ -106,6 +109,32 @@ nsSVGPathGeometryFrame::GetType() const
|
||||
return nsGkAtoms::svgPathGeometryFrame;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGPathGeometryFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
|
||||
gfxMatrix *aFromParentTransform) const
|
||||
{
|
||||
bool foundTransform = false;
|
||||
|
||||
// Check if our parent has children-only transforms:
|
||||
nsIFrame *parent = GetParent();
|
||||
if (parent &&
|
||||
parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
|
||||
foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
|
||||
HasChildrenOnlyTransform(aFromParentTransform);
|
||||
}
|
||||
|
||||
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
|
||||
const SVGAnimatedTransformList *list = content->GetAnimatedTransformList();
|
||||
if (list && !list->GetAnimValue().IsEmpty()) {
|
||||
if (aOwnTransform) {
|
||||
*aOwnTransform = content->PrependLocalTransformsTo(gfxMatrix(),
|
||||
nsSVGElement::eUserSpaceToParent);
|
||||
}
|
||||
foundTransform = true;
|
||||
}
|
||||
return foundTransform;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGChildFrame methods
|
||||
|
||||
@ -235,9 +264,22 @@ nsSVGPathGeometryFrame::UpdateBounds()
|
||||
mCoveredRegion = nsSVGUtils::TransformFrameRectToOuterSVG(
|
||||
mRect, GetCanvasTM(), PresContext());
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
// Make sure we have our filter property (if any) before calling
|
||||
// FinishAndStoreOverflow (subsequent filter changes are handled off
|
||||
// nsChangeHint_UpdateEffects):
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
|
||||
nsOverflowAreas overflowAreas(overflow, overflow);
|
||||
FinishAndStoreOverflow(overflowAreas, mRect.Size());
|
||||
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
// XXXSDL get rid of this in favor of the invalidate call in
|
||||
// FinishAndStoreOverflow?
|
||||
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
// We only invalidate if our outer-<svg> has already had its
|
||||
// initial reflow (since if it hasn't, its entire area will be
|
||||
|
@ -68,8 +68,11 @@ class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
|
||||
friend nsIFrame*
|
||||
NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||
protected:
|
||||
nsSVGPathGeometryFrame(nsStyleContext* aContext) :
|
||||
nsSVGPathGeometryFrameBase(aContext) {}
|
||||
nsSVGPathGeometryFrame(nsStyleContext* aContext)
|
||||
: nsSVGPathGeometryFrameBase(aContext)
|
||||
{
|
||||
AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_QUERYFRAME
|
||||
@ -89,6 +92,9 @@ public:
|
||||
*/
|
||||
virtual nsIAtom* GetType() const;
|
||||
|
||||
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransforms = nsnull,
|
||||
gfxMatrix *aFromParentTransforms = nsnull) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD GetFrameName(nsAString& aResult) const
|
||||
{
|
||||
@ -110,9 +116,6 @@ protected:
|
||||
virtual SVGBBox GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
PRUint32 aFlags);
|
||||
NS_IMETHOD_(bool) IsDisplayContainer() { return false; }
|
||||
NS_IMETHOD_(bool) HasValidCoveredRect() {
|
||||
return !(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
|
||||
}
|
||||
|
||||
protected:
|
||||
void GeneratePath(gfxContext *aContext,
|
||||
|
@ -39,6 +39,7 @@
|
||||
// Keep in (case-insensitive) order:
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxRect.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsSVGGFrame.h"
|
||||
#include "nsSVGSwitchElement.h"
|
||||
#include "nsSVGUtils.h"
|
||||
@ -82,6 +83,7 @@ public:
|
||||
NS_IMETHOD PaintSVG(nsRenderingContext* aContext, const nsIntRect *aDirtyRect);
|
||||
NS_IMETHODIMP_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
|
||||
NS_IMETHODIMP_(nsRect) GetCoveredRegion();
|
||||
virtual void UpdateBounds();
|
||||
virtual SVGBBox GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
PRUint32 aFlags);
|
||||
|
||||
@ -164,6 +166,68 @@ nsSVGSwitchFrame::GetCoveredRegion()
|
||||
return rect;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSwitchFrame::UpdateBounds()
|
||||
{
|
||||
NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this),
|
||||
"This call is probaby a wasteful mistake");
|
||||
|
||||
NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
|
||||
"UpdateBounds mechanism not designed for this");
|
||||
|
||||
if (!nsSVGUtils::NeedsUpdatedBounds(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the NS_FRAME_FIRST_REFLOW bit has been removed from our parent frame,
|
||||
// then our outer-<svg> has previously had its initial reflow. In that case
|
||||
// we need to make sure that that bit has been removed from ourself _before_
|
||||
// recursing over our children to ensure that they know too. Otherwise, we
|
||||
// need to remove it _after_ recursing over our children so that they know
|
||||
// the initial reflow is currently underway.
|
||||
|
||||
bool outerSVGHasHadFirstReflow =
|
||||
(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) == 0;
|
||||
|
||||
if (outerSVGHasHadFirstReflow) {
|
||||
mState &= ~NS_FRAME_FIRST_REFLOW; // tell our children
|
||||
}
|
||||
|
||||
nsOverflowAreas overflowRects;
|
||||
|
||||
nsIFrame *child = GetActiveChildFrame();
|
||||
if (child) {
|
||||
nsISVGChildFrame* svgChild = do_QueryFrame(child);
|
||||
if (svgChild) {
|
||||
NS_ABORT_IF_FALSE(!(child->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
|
||||
"Check for this explicitly in the |if|, then");
|
||||
svgChild->UpdateBounds();
|
||||
|
||||
// We build up our child frame overflows here instead of using
|
||||
// nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same
|
||||
// frame list, and we're iterating over that list now anyway.
|
||||
ConsiderChildOverflow(overflowRects, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
// Make sure we have our filter property (if any) before calling
|
||||
// FinishAndStoreOverflow (subsequent filter changes are handled off
|
||||
// nsChangeHint_UpdateEffects):
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
FinishAndStoreOverflow(overflowRects, mRect.Size());
|
||||
|
||||
// Remove state bits after FinishAndStoreOverflow so that it doesn't
|
||||
// invalidate on first reflow:
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
// XXXSDL Make Invalidate() call nsSVGUtils::InvalidateBounds(this)
|
||||
// so that we invalidate under FinishAndStoreOverflow().
|
||||
}
|
||||
|
||||
SVGBBox
|
||||
nsSVGSwitchFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
PRUint32 aFlags)
|
||||
|
@ -257,7 +257,7 @@ nsSVGTextFrame::UpdateBounds()
|
||||
// areas correctly:
|
||||
nsSVGTextFrameBase::UpdateBounds();
|
||||
|
||||
// XXXsvgreflow once we store bounds on containers, call
|
||||
// XXXSDL once we store bounds on containers, call
|
||||
// nsSVGUtils::InvalidateBounds(this) if not first reflow.
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
#endif
|
||||
|
||||
// nsISVGChildFrame interface:
|
||||
virtual void UpdateBounds();
|
||||
virtual void NotifySVGChanged(PRUint32 aFlags);
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
@ -195,6 +196,21 @@ nsSVGUseFrame::IsLeaf() const
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGChildFrame methods
|
||||
|
||||
void
|
||||
nsSVGUseFrame::UpdateBounds()
|
||||
{
|
||||
// We only handle x/y offset here, since any width/height that is in force is
|
||||
// handled by the nsSVGOuterSVGFrame for the anonymous <svg> that will be
|
||||
// created for that purpose.
|
||||
float x, y;
|
||||
static_cast<nsSVGUseElement*>(mContent)->
|
||||
GetAnimatedLengthValues(&x, &y, nsnull);
|
||||
mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect(
|
||||
gfxRect(x, y, 0.0, 0.0),
|
||||
PresContext()->AppUnitsPerCSSPixel()).TopLeft());
|
||||
nsSVGUseFrameBase::UpdateBounds();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGUseFrame::NotifySVGChanged(PRUint32 aFlags)
|
||||
{
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsFrameList.h"
|
||||
@ -64,6 +65,7 @@
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsSVGAnimationElement.h"
|
||||
#include "nsSVGClipPathFrame.h"
|
||||
#include "nsSVGContainerFrame.h"
|
||||
#include "nsSVGEffects.h"
|
||||
@ -160,31 +162,26 @@ static const PRUint8 gsRGBToLinearRGBMap[256] = {
|
||||
239, 242, 244, 246, 248, 250, 253, 255
|
||||
};
|
||||
|
||||
static bool gSMILEnabled;
|
||||
static const char SMIL_PREF_STR[] = "svg.smil.enabled";
|
||||
|
||||
static int
|
||||
SMILPrefChanged(const char *aPref, void *aClosure)
|
||||
{
|
||||
bool prefVal = Preferences::GetBool(SMIL_PREF_STR);
|
||||
gSMILEnabled = prefVal;
|
||||
return 0;
|
||||
}
|
||||
static bool sSMILEnabled;
|
||||
static bool sSVGDisplayListHitTestingEnabled;
|
||||
static bool sSVGDisplayListPaintingEnabled;
|
||||
|
||||
bool
|
||||
NS_SMILEnabled()
|
||||
{
|
||||
static bool sInitialized = false;
|
||||
|
||||
if (!sInitialized) {
|
||||
/* check and register ourselves with the pref */
|
||||
gSMILEnabled = Preferences::GetBool(SMIL_PREF_STR);
|
||||
Preferences::RegisterCallback(SMILPrefChanged, SMIL_PREF_STR);
|
||||
return sSMILEnabled;
|
||||
}
|
||||
|
||||
sInitialized = true;
|
||||
}
|
||||
bool
|
||||
NS_SVGDisplayListHitTestingEnabled()
|
||||
{
|
||||
return sSVGDisplayListHitTestingEnabled;
|
||||
}
|
||||
|
||||
return gSMILEnabled;
|
||||
bool
|
||||
NS_SVGDisplayListPaintingEnabled()
|
||||
{
|
||||
return sSVGDisplayListPaintingEnabled;
|
||||
}
|
||||
|
||||
// we only take the address of this:
|
||||
@ -237,6 +234,20 @@ SVGAutoRenderState::IsPaintingToWindow(nsRenderingContext *aContext)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGUtils::Init()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&sSMILEnabled,
|
||||
"svg.smil.enabled",
|
||||
true);
|
||||
|
||||
Preferences::AddBoolVarCache(&sSVGDisplayListHitTestingEnabled,
|
||||
"svg.display-lists.hit-testing.enabled");
|
||||
|
||||
Preferences::AddBoolVarCache(&sSVGDisplayListPaintingEnabled,
|
||||
"svg.display-lists.painting.enabled");
|
||||
}
|
||||
|
||||
nsSVGSVGElement*
|
||||
nsSVGUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
|
||||
{
|
||||
@ -255,6 +266,15 @@ nsSVGUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGUtils::ActivateByHyperlink(nsIContent *aContent)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aContent->IsNodeOfType(nsINode::eANIMATION),
|
||||
"Expecting an animation element");
|
||||
|
||||
static_cast<nsSVGAnimationElement*>(aContent)->ActivateByHyperlink();
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::GetFontSize(Element *aElement)
|
||||
{
|
||||
@ -578,6 +598,26 @@ nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGUtils::GetPostFilterVisualOverflowRect(nsIFrame *aFrame,
|
||||
const nsRect &aUnfilteredRect)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT,
|
||||
"Called on invalid frame type");
|
||||
|
||||
nsSVGFilterFrame *filter = nsSVGEffects::GetFilterFrame(aFrame);
|
||||
if (!filter) {
|
||||
return aUnfilteredRect;
|
||||
}
|
||||
|
||||
PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsIntRect unfilteredRect =
|
||||
aUnfilteredRect.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
nsIntRect rect = filter->GetFilterBBox(aFrame, nsnull, &unfilteredRect);
|
||||
nsRect r = rect.ToAppUnits(appUnitsPerDevPixel) - aFrame->GetPosition();
|
||||
return r;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
|
||||
{
|
||||
@ -687,7 +727,7 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate)
|
||||
return;
|
||||
}
|
||||
|
||||
// XXXsvgreflow we want to reduce the bounds when passing through inner-<svg>
|
||||
// XXXSDL we want to reduce the bounds when passing through inner-<svg>
|
||||
// and <use>, etc.
|
||||
|
||||
nsSVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame(aFrame);
|
||||
@ -753,7 +793,7 @@ nsSVGUtils::ScheduleBoundsUpdate(nsIFrame *aFrame)
|
||||
return;
|
||||
}
|
||||
|
||||
// XXXsvgreflow once we store bounds on containers, we will not need to
|
||||
// XXXSDL once we store bounds on containers, we will not need to
|
||||
// mark our descendants dirty.
|
||||
MarkDirtyBitsOnDescendants(aFrame);
|
||||
|
||||
@ -1135,20 +1175,33 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
|
||||
bool isOK = true;
|
||||
nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
|
||||
|
||||
/* Check if we need to draw anything. HasValidCoveredRect only returns
|
||||
* true for path geometry and glyphs, so basically we're traversing
|
||||
* all containers and we can only skip leaves here.
|
||||
*/
|
||||
if (aDirtyRect && svgChildFrame->HasValidCoveredRect()) {
|
||||
if (filterFrame) {
|
||||
if (!aDirtyRect->Intersects(filterFrame->GetFilterBBox(aFrame, nsnull)))
|
||||
return;
|
||||
} else {
|
||||
nsRect leafBounds = nsSVGUtils::TransformFrameRectToOuterSVG(
|
||||
aFrame->GetRect(), GetCanvasTM(aFrame), aFrame->PresContext());
|
||||
nsRect rect = aDirtyRect->ToAppUnits(aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
if (!rect.Intersects(leafBounds))
|
||||
return;
|
||||
if (aDirtyRect &&
|
||||
!(aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
||||
// Here we convert aFrame's paint bounds to outer-<svg> device space,
|
||||
// compare it to aDirtyRect, and return early if they don't intersect.
|
||||
// We don't do this optimization for nondisplay SVG since nondisplay
|
||||
// SVG doesn't maintain bounds/overflow rects.
|
||||
nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry)) {
|
||||
// Unlike containers, leaf frames do not include GetPosition() in
|
||||
// GetCanvasTM().
|
||||
overflowRect = overflowRect + aFrame->GetPosition();
|
||||
}
|
||||
PRUint32 appUnitsPerDevPx = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
gfxMatrix tm = GetCanvasTM(aFrame);
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
|
||||
gfxMatrix childrenOnlyTM;
|
||||
if (static_cast<nsSVGContainerFrame*>(aFrame)->
|
||||
HasChildrenOnlyTransform(&childrenOnlyTM)) {
|
||||
// Undo the children-only transform:
|
||||
tm = childrenOnlyTM.Invert() * tm;
|
||||
}
|
||||
}
|
||||
nsIntRect bounds = nsSVGUtils::TransformFrameRectToOuterSVG(overflowRect,
|
||||
tm, aFrame->PresContext()).
|
||||
ToOutsidePixels(appUnitsPerDevPx);
|
||||
if (!aDirtyRect->Intersects(bounds)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "gfxPoint.h"
|
||||
#include "gfxRect.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsID.h"
|
||||
@ -143,6 +144,9 @@ IsSVGWhitespace(PRUnichar aChar)
|
||||
*/
|
||||
bool NS_SMILEnabled();
|
||||
|
||||
bool NS_SVGDisplayListHitTestingEnabled();
|
||||
bool NS_SVGDisplayListPaintingEnabled();
|
||||
|
||||
/**
|
||||
* Sometimes we need to distinguish between an empty box and a box
|
||||
* that contains an element that has no size e.g. a point at the origin.
|
||||
@ -225,6 +229,8 @@ public:
|
||||
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
|
||||
typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
|
||||
|
||||
static void Init();
|
||||
|
||||
/*
|
||||
* Get the parent element of an nsIContent
|
||||
*/
|
||||
@ -235,6 +241,16 @@ public:
|
||||
*/
|
||||
static nsSVGSVGElement *GetOuterSVGElement(nsSVGElement *aSVGElement);
|
||||
|
||||
/**
|
||||
* Activates the animation element aContent as a result of navigation to the
|
||||
* fragment identifier that identifies aContent. aContent must be an instance
|
||||
* of nsSVGAnimationElement.
|
||||
*
|
||||
* This is just a shim to allow nsSVGAnimationElement::ActivateByHyperlink to
|
||||
* be called from layout/base without adding to that directory's include paths.
|
||||
*/
|
||||
static void ActivateByHyperlink(nsIContent *aContent);
|
||||
|
||||
/*
|
||||
* Get the number of CSS px (user units) per em (i.e. the em-height in user
|
||||
* units) for an nsIContent
|
||||
@ -315,7 +331,15 @@ public:
|
||||
* returns nsnull.
|
||||
*/
|
||||
static nsSVGDisplayContainerFrame* GetNearestSVGViewport(nsIFrame *aFrame);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the frame's post-filter visual overflow rect when passed the
|
||||
* frame's pre-filter visual overflow rect. If the frame is not currently
|
||||
* being filtered, this function simply returns aUnfilteredRect.
|
||||
*/
|
||||
static nsRect GetPostFilterVisualOverflowRect(nsIFrame *aFrame,
|
||||
const nsRect &aUnfilteredRect);
|
||||
|
||||
/**
|
||||
* Figures out the worst case invalidation area for a frame, taking
|
||||
* filters into account.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user