Merge last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-05-17 14:01:53 -04:00
commit e520960d8b
134 changed files with 5350 additions and 1452 deletions

View File

@ -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;

View File

@ -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.
*/

View File

@ -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())) {

View File

@ -96,7 +96,7 @@ public:
// nsAccessible
virtual void Value(nsString& aValue);
virtual PRUint64 NativeState();
virtual PRUint64 NativeLinkState() const;
// ActionAccessible
virtual PRUint8 ActionCount();

View File

@ -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
//

View File

@ -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);

View File

@ -1045,7 +1045,7 @@ ARIAGridCellAccessible::IsSelected(bool* aIsSelected)
// nsAccessible
void
ARIAGridCellAccessible::ApplyARIAState(PRUint64* aState)
ARIAGridCellAccessible::ApplyARIAState(PRUint64* aState) const
{
nsHyperTextAccessibleWrap::ApplyARIAState(aState);

View File

@ -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);
};

View File

@ -333,7 +333,7 @@ ApplicationAccessible::IsPrimaryForNode() const
// nsAccessible public methods
void
ApplicationAccessible::ApplyARIAState(PRUint64* aState)
ApplicationAccessible::ApplyARIAState(PRUint64* aState) const
{
}

View File

@ -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();

View File

@ -437,7 +437,7 @@ HTMLTextFieldAccessible::Value(nsString& aValue)
}
void
HTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState)
HTMLTextFieldAccessible::ApplyARIAState(PRUint64* aState) const
{
nsHyperTextAccessibleWrap::ApplyARIAState(aState);

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -178,9 +178,9 @@ nsXULLinkAccessible::NativeRole()
PRUint64
nsXULLinkAccessible::NativeState()
nsXULLinkAccessible::NativeLinkState() const
{
return nsHyperTextAccessible::NativeState() | states::LINKED;
return states::LINKED;
}
PRUint8

View File

@ -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();

View File

@ -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>

View File

@ -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")

View File

@ -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

View File

@ -54,6 +54,7 @@ EXPORTS = \
nsEventDispatcher.h \
nsEventStates.h \
nsEventNameList.h \
nsVKList.h \
$(NULL)
XPIDLSRCS = \

View 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

View File

@ -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);
}

View File

@ -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.

View File

@ -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 \

View 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>

View File

@ -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 \

View File

@ -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

View File

@ -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

View 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 &params =
Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
if (IsMatchingParameter(token, NS_LITERAL_STRING("viewBox"))) {
if (viewBoxParams) {
return false;
}
viewBoxParams = &params;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
if (preserveAspectRatioParams) {
return false;
}
preserveAspectRatioParams = &params;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
if (zoomAndPanParams) {
return false;
}
zoomAndPanParams = &params;
} 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;
}

View 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__

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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,

View 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));
}

View 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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -131,6 +131,7 @@ XPIDLSRCS = \
nsIDOMSVGURIReference.idl \
nsIDOMSVGUnitTypes.idl \
nsIDOMSVGUseElement.idl \
nsIDOMSVGViewElement.idl \
nsIDOMSVGViewSpec.idl \
nsIDOMSVGZoomAndPan.idl \
nsIDOMSVGZoomEvent.idl \

View 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;
};

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -68,7 +68,7 @@
namespace js {
class AutoPropDescArrayRooter;
class ProxyHandler;
class BaseProxyHandler;
class CallObject;
struct GCMarker;
struct NativeIterator;

View File

@ -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_);

View File

@ -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);

View File

@ -182,7 +182,7 @@ struct TreeContext;
class UpvarCookie;
class Proxy;
class ProxyHandler;
class BaseProxyHandler;
class Wrapper;
class CrossCompartmentWrapper;

View File

@ -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)
{
}

View File

@ -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;

View File

@ -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) {

View File

@ -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}"

View File

@ -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>

View File

@ -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>

View File

@ -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()));

View File

@ -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

View File

@ -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) {

View File

@ -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.

View File

@ -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),

View File

@ -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

View File

@ -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");

View File

@ -270,6 +270,8 @@ nsLayoutStatics::Initialize()
nsWindowMemoryReporter::Init();
nsSVGUtils::Init();
return NS_OK;
}

View File

@ -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

View File

@ -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()

View 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>

View 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

View File

@ -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

View File

@ -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::

View File

@ -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__

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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.
}

View File

@ -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)
{

View File

@ -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;
}
}

View File

@ -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