зеркало из https://github.com/mozilla/pjs.git
Bug 515116. DeCOMify SVG length-list, and implement SMIL animation of length-list. r=longsonr, r=dholbert, sr=roc
This commit is contained in:
Родитель
57530a5bc7
Коммит
cf27411a13
|
@ -52,9 +52,12 @@ class nsSMILValue;
|
|||
// the data upon which it should operate.
|
||||
//
|
||||
// We keep the data and type separate rather than just providing different
|
||||
// subclasses of nsSMILValue as this allows nsSMILValues to be allocated on the
|
||||
// stack and directly assigned to one another provided performance benefits for
|
||||
// the animation code.
|
||||
// subclasses of nsSMILValue. This is so that sizeof(nsSMILValue) is the same
|
||||
// for all value types, allowing us to have a type-agnostic nsTArray of
|
||||
// nsSMILValue objects (actual objects, not pointers). It also allows most
|
||||
// nsSMILValues (except those that need to allocate extra memory for their
|
||||
// data) to be allocated on the stack and directly assigned to one another
|
||||
// provided performance benefits for the animation code.
|
||||
//
|
||||
// Note that different types have different capabilities. Roughly speaking there
|
||||
// are probably three main types:
|
||||
|
|
|
@ -42,6 +42,15 @@
|
|||
#include "nsISMILType.h"
|
||||
#include "nsSMILNullType.h"
|
||||
|
||||
/**
|
||||
* Although objects of this type are generally only created on the stack and
|
||||
* only exist during the taking of a new time sample, that's not always the
|
||||
* case. The nsSMILValue objects obtained from attributes' base values are
|
||||
* cached so that the SMIL engine can make certain optimizations during a
|
||||
* sample if the base value has not changed since the last sample (potentially
|
||||
* avoiding recomposing). These nsSMILValue objects typically live much longer
|
||||
* than a single sample.
|
||||
*/
|
||||
class nsSMILValue
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "DOMSVGLengthList.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsSVGAttrTearoffTable.h"
|
||||
|
||||
// See the architecture comment in this file's header.
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static nsSVGAttrTearoffTable<SVGAnimatedLengthList, DOMSVGAnimatedLengthList>
|
||||
sSVGAnimatedLengthListTearoffTable;
|
||||
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGAnimatedLengthList, mElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedLengthList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedLengthList)
|
||||
|
||||
}
|
||||
DOMCI_DATA(SVGAnimatedLengthList, DOMSVGAnimatedLengthList)
|
||||
namespace mozilla {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGAnimatedLengthList::GetBaseVal(nsIDOMSVGLengthList **_retval)
|
||||
{
|
||||
if (!mBaseVal) {
|
||||
mBaseVal = new DOMSVGLengthList(this);
|
||||
}
|
||||
NS_ADDREF(*_retval = mBaseVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGAnimatedLengthList::GetAnimVal(nsIDOMSVGLengthList **_retval)
|
||||
{
|
||||
if (!mAnimVal) {
|
||||
mAnimVal = new DOMSVGLengthList(this);
|
||||
}
|
||||
NS_ADDREF(*_retval = mAnimVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<DOMSVGAnimatedLengthList>
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapper(SVGAnimatedLengthList *aList,
|
||||
nsSVGElement *aElement,
|
||||
PRUint8 aAttrEnum,
|
||||
PRUint8 aAxis)
|
||||
{
|
||||
DOMSVGAnimatedLengthList *wrapper =
|
||||
sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
|
||||
if (!wrapper) {
|
||||
wrapper = new DOMSVGAnimatedLengthList(aElement, aAttrEnum, aAxis);
|
||||
sSVGAnimatedLengthListTearoffTable.AddTearoff(aList, wrapper);
|
||||
}
|
||||
NS_ADDREF(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/* static */ DOMSVGAnimatedLengthList*
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(SVGAnimatedLengthList *aList)
|
||||
{
|
||||
return sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
|
||||
}
|
||||
|
||||
DOMSVGAnimatedLengthList::~DOMSVGAnimatedLengthList()
|
||||
{
|
||||
// Script no longer has any references to us, to our base/animVal objects, or
|
||||
// to any of their list items.
|
||||
sSVGAnimatedLengthListTearoffTable.RemoveTearoff(&InternalAList());
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGAnimatedLengthList::InternalBaseValListWillChangeTo(const SVGLengthList& aNewValue)
|
||||
{
|
||||
// When the number of items in our internal counterpart's baseVal changes,
|
||||
// we MUST keep our baseVal in sync. If we don't, script will either see a
|
||||
// list that is too short and be unable to access indexes that should be
|
||||
// valid, or else, MUCH WORSE, script will see a list that is too long and be
|
||||
// able to access "items" at indexes that are out of bounds (read/write to
|
||||
// bad memory)!!
|
||||
|
||||
if (mBaseVal) {
|
||||
mBaseVal->InternalListLengthWillChange(aNewValue.Length());
|
||||
}
|
||||
|
||||
// If our attribute is not animating, then our animVal mirrors our baseVal
|
||||
// and we must sync its length too. (If our attribute is animating, then the
|
||||
// SMIL engine takes care of calling InternalAnimValListWillChangeTo() if
|
||||
// necessary.)
|
||||
|
||||
if (!IsAnimating()) {
|
||||
InternalAnimValListWillChangeTo(aNewValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGAnimatedLengthList::InternalAnimValListWillChangeTo(const SVGLengthList& aNewValue)
|
||||
{
|
||||
if (mAnimVal) {
|
||||
mAnimVal->InternalListLengthWillChange(aNewValue.Length());
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
DOMSVGAnimatedLengthList::IsAnimating() const
|
||||
{
|
||||
return InternalAList().IsAnimating();
|
||||
}
|
||||
|
||||
SVGAnimatedLengthList&
|
||||
DOMSVGAnimatedLengthList::InternalAList()
|
||||
{
|
||||
return *mElement->GetAnimatedLengthList(mAttrEnum);
|
||||
}
|
||||
|
||||
const SVGAnimatedLengthList&
|
||||
DOMSVGAnimatedLengthList::InternalAList() const
|
||||
{
|
||||
return *mElement->GetAnimatedLengthList(mAttrEnum);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,229 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_DOMSVGANIMATEDLENGTHLIST_H__
|
||||
#define MOZILLA_DOMSVGANIMATEDLENGTHLIST_H__
|
||||
|
||||
#include "nsIDOMSVGAnimatedLengthList.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SVGAnimatedLengthList;
|
||||
class SVGLengthList;
|
||||
class DOMSVGLengthList;
|
||||
|
||||
/**
|
||||
* Class DOMSVGAnimatedLengthList
|
||||
*
|
||||
* This class is used to create the DOM tearoff objects that wrap internal
|
||||
* SVGAnimatedLengthList objects. We have this internal-DOM split because DOM
|
||||
* classes are relatively heavy-weight objects with non-optimal interfaces for
|
||||
* internal code, and they're relatively infrequently used. Having separate
|
||||
* internal and DOM classes does add complexity - especially for lists where
|
||||
* the internal list and DOM lists (and their items) need to be kept in sync -
|
||||
* but it keeps the internal classes light and fast, and in 99% of cases
|
||||
* they're all that's used. DOM wrappers are only instantiated when script
|
||||
* demands it.
|
||||
*
|
||||
* Ownership model:
|
||||
*
|
||||
* The diagram below shows the ownership model between the various DOM objects
|
||||
* in the tree of DOM objects that correspond to an SVG length list attribute.
|
||||
* The angled brackets ">" and "<" denote a reference from one object to
|
||||
* another, where the "!" character denotes a strong reference, and the "~"
|
||||
* character denotes a weak reference.
|
||||
*
|
||||
* .----<!----. .----<!----. .----<!----.
|
||||
* | | | | | |
|
||||
* element ~> DOMSVGAnimatedLengthList ~> DOMSVGLengthList ~> DOMSVGLength
|
||||
*
|
||||
* Rational:
|
||||
*
|
||||
* The following three paragraphs explain the main three requirements that must
|
||||
* be met by any design. These are followed by an explanation of the rational
|
||||
* behind our particular design.
|
||||
*
|
||||
* 1: DOMSVGAnimatedLengthList, DOMSVGLengthLists and DOMSVGLength get to their
|
||||
* internal counterparts via their element, and they use their element to send
|
||||
* out appropriate notifications when they change. Because of this, having
|
||||
* their element disappear out from under them would be very bad. To keep their
|
||||
* element alive at least as long as themselves, each of these classes must
|
||||
* contain a _strong_ reference (directly or indirectly) to their element.
|
||||
*
|
||||
* 2: Another central requirement of any design is the SVG specification's
|
||||
* requirement that script must always be given the exact same objects each
|
||||
* time it accesses a given object in a DOM object tree corresponding to an SVG
|
||||
* length list attribute. In practice "always" actually means "whenever script
|
||||
* has kept a references to a DOM object it previously accessed", since a
|
||||
* script will only be able to detect any difference in object identity if it
|
||||
* has a previous reference to compare against.
|
||||
*
|
||||
* 3: The wiggle room in the "same object" requirement leads us to a third
|
||||
* (self imposed) requirement: if script no longer has a reference to a given
|
||||
* DOM object from an object tree corresponding to an SVG length list
|
||||
* attribute, and if that object doesn't currently have any descendants, then
|
||||
* that object should be released to free up memory.
|
||||
*
|
||||
* To help in understanding our current design, consider this BROKEN design:
|
||||
*
|
||||
* .-------------------------------<!-------------------------.
|
||||
* |--------------------<!----------------. |
|
||||
* |----<!----. | |
|
||||
* | | | |
|
||||
* element ~> DOMSVGAnimatedLengthList !> DOMSVGLengthList !> DOMSVGLength
|
||||
*
|
||||
* Having all the objects keep a reference directly to their element like this
|
||||
* would reduce the number of dereferences that they need to make to get their
|
||||
* internal counterpart. Hovewer, this design does not meet the "same object"
|
||||
* requirement of the SVG specification. If script keeps a reference to a
|
||||
* DOMSVGLength or DOMSVGLengthList object, but not to that object's
|
||||
* DOMSVGAnimatedLengthList, then the DOMSVGAnimatedLengthList may be garbage
|
||||
* collected. We'd then have no way to return the same DOMSVGLength /
|
||||
* DOMSVGLengthList object that the script has a reference to if the script
|
||||
* went looking for it via the DOMSVGAnimatedLengthList property on the
|
||||
* element - we'd end up creating a fresh DOMSVGAnimatedLengthList, with no
|
||||
* knowlegde of the existing DOMSVGLengthList or DOMSVGLength object.
|
||||
*
|
||||
* The way we solve this problem is by making sure that parent objects cannot
|
||||
* die until all their children are dead by having child objects hold a strong
|
||||
* reference to their parent object. Note that this design means that the child
|
||||
* objects hold a strong reference to their element too, albeit indirectly via
|
||||
* the strong reference to their parent object:
|
||||
*
|
||||
* .----<!----. .----<!----. .----<!----.
|
||||
* | | | | | |
|
||||
* element ~> DOMSVGAnimatedLengthList ~> DOMSVGLengthList ~> DOMSVGLength
|
||||
*
|
||||
* One drawback of this design is that objects must look up their parent
|
||||
* chain to find their element, but that overhead is relatively small.
|
||||
*/
|
||||
class DOMSVGAnimatedLengthList : public nsIDOMSVGAnimatedLengthList
|
||||
{
|
||||
friend class DOMSVGLengthList;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGAnimatedLengthList)
|
||||
NS_DECL_NSIDOMSVGANIMATEDLENGTHLIST
|
||||
|
||||
/**
|
||||
* Factory method to create and return a DOMSVGAnimatedLengthList wrapper
|
||||
* for a given internal SVGAnimatedLengthList object. The factory takes care
|
||||
* of caching the object that it returns so that the same object can be
|
||||
* returned for the given SVGAnimatedLengthList each time it is requested.
|
||||
* The cached object is only removed from the cache when it is destroyed due
|
||||
* to there being no more references to it or to any of its descendant
|
||||
* objects. If that happens, any subsequent call requesting the DOM wrapper
|
||||
* for the SVGAnimatedLengthList will naturally result in a new
|
||||
* DOMSVGAnimatedLengthList being returned.
|
||||
*/
|
||||
static already_AddRefed<DOMSVGAnimatedLengthList>
|
||||
GetDOMWrapper(SVGAnimatedLengthList *aList,
|
||||
nsSVGElement *aElement,
|
||||
PRUint8 aAttrEnum,
|
||||
PRUint8 aAxis);
|
||||
|
||||
/**
|
||||
* This method returns the DOMSVGAnimatedLengthList wrapper for an internal
|
||||
* SVGAnimatedLengthList object if it currently has a wrapper. If it does
|
||||
* not, then nsnull is returned.
|
||||
*/
|
||||
static DOMSVGAnimatedLengthList*
|
||||
GetDOMWrapperIfExists(SVGAnimatedLengthList *aList);
|
||||
|
||||
/**
|
||||
* Called by internal code to notify us when we need to sync the length of
|
||||
* our baseVal DOM list with its internal list. This is called just prior to
|
||||
* the length of the internal baseVal list being changed so that any DOM list
|
||||
* items that need to be removed from the DOM list can first get their values
|
||||
* from their internal counterpart.
|
||||
*
|
||||
* The only time this method could fail is on OOM when trying to increase the
|
||||
* length of the DOM list. If that happens then this method simply clears the
|
||||
* list and returns. Callers just proceed as normal, and we simply accept
|
||||
* that the DOM list will be empty (until successfully set to a new value).
|
||||
*/
|
||||
void InternalBaseValListWillChangeTo(const SVGLengthList& aNewValue);
|
||||
void InternalAnimValListWillChangeTo(const SVGLengthList& aNewValue);
|
||||
|
||||
/**
|
||||
* Returns true if our attribute is animating (in which case our animVal is
|
||||
* not simply a mirror of our baseVal).
|
||||
*/
|
||||
PRBool IsAnimating() const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Only our static GetDOMWrapper() factory method may create objects of our
|
||||
* type.
|
||||
*/
|
||||
DOMSVGAnimatedLengthList(nsSVGElement *aElement, PRUint8 aAttrEnum, PRUint8 aAxis)
|
||||
: mBaseVal(nsnull)
|
||||
, mAnimVal(nsnull)
|
||||
, mElement(aElement)
|
||||
, mAttrEnum(aAttrEnum)
|
||||
, mAxis(aAxis)
|
||||
{}
|
||||
|
||||
~DOMSVGAnimatedLengthList();
|
||||
|
||||
/// Get a reference to this DOM wrapper object's internal counterpart.
|
||||
SVGAnimatedLengthList& InternalAList();
|
||||
const SVGAnimatedLengthList& InternalAList() const;
|
||||
|
||||
// Weak refs to our DOMSVGLengthList baseVal/animVal objects. These objects
|
||||
// are friends and take care of clearing these pointers when they die, making
|
||||
// these true weak references.
|
||||
DOMSVGLengthList *mBaseVal;
|
||||
DOMSVGLengthList *mAnimVal;
|
||||
|
||||
// Strong ref to our element to keep it alive. We hold this not only for
|
||||
// ourself, but also for our base/animVal and all of their items.
|
||||
nsRefPtr<nsSVGElement> mElement;
|
||||
|
||||
PRUint8 mAttrEnum;
|
||||
PRUint8 mAxis;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DOMSVGANIMATEDLENGTHLIST_H__
|
|
@ -0,0 +1,364 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "DOMSVGLength.h"
|
||||
#include "DOMSVGLengthList.h"
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "SVGLength.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsDOMError.h"
|
||||
|
||||
// See the architecture comment in DOMSVGAnimatedLengthList.h.
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
|
||||
// clear our list's weak ref to us to be safe. (The other option would be to
|
||||
// not unlink and rely on the breaking of the other edges in the cycle, as
|
||||
// NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLength)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLength)
|
||||
// We may not belong to a list, so we must null check tmp->mList.
|
||||
if (tmp->mList) {
|
||||
tmp->mList->mItems[tmp->mListIndex] = nsnull;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLength)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGLength)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGLength)
|
||||
|
||||
}
|
||||
DOMCI_DATA(SVGLength, DOMSVGLength)
|
||||
namespace mozilla {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLength)
|
||||
NS_INTERFACE_MAP_ENTRY(DOMSVGLength) // pseudo-interface
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
DOMSVGLength::DOMSVGLength(DOMSVGLengthList *aList,
|
||||
PRUint32 aAttrEnum,
|
||||
PRUint8 aListIndex,
|
||||
PRUint8 aIsAnimValItem)
|
||||
: mList(aList)
|
||||
, mListIndex(aListIndex)
|
||||
, mAttrEnum(aAttrEnum)
|
||||
, mIsAnimValItem(aIsAnimValItem)
|
||||
, mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
|
||||
, mValue(0.0f)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// These shifts are in sync with the flag member's in the header.
|
||||
NS_ABORT_IF_FALSE(aList &&
|
||||
aAttrEnum < (1 << 22) &&
|
||||
aListIndex < (1 << 4) &&
|
||||
aIsAnimValItem < (1 << 1), "bad arg");
|
||||
if (aIsAnimValItem &&
|
||||
mListIndex >= Element()->GetAnimatedLengthList(mAttrEnum)->GetAnimValue().Length() ||
|
||||
!aIsAnimValItem &&
|
||||
mListIndex >= Element()->GetAnimatedLengthList(mAttrEnum)->GetBaseValue().Length()) {
|
||||
NS_ABORT_IF_FALSE(0, "Bad aListIndex!");
|
||||
mList = nsnull;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DOMSVGLength::DOMSVGLength()
|
||||
: mList(nsnull)
|
||||
, mListIndex(0)
|
||||
, mAttrEnum(0)
|
||||
, mIsAnimValItem(0)
|
||||
, mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
|
||||
, mValue(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::GetUnitType(PRUint16* aUnit)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimValItem && HasOwner()) {
|
||||
Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
|
||||
}
|
||||
#endif
|
||||
*aUnit = HasOwner() ? InternalItem().GetUnit() : mUnit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::GetValue(float* aValue)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimValItem && HasOwner()) {
|
||||
Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
|
||||
}
|
||||
#endif
|
||||
if (HasOwner()) {
|
||||
*aValue = InternalItem().GetValueInUserUnits(Element(), Axis());
|
||||
if (NS_FloatIsFinite(*aValue)) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
|
||||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
|
||||
*aValue = mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
// else [SVGWG issue] Can't convert this length's value to user units
|
||||
// ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::SetValue(float aUserUnitValue)
|
||||
{
|
||||
if (mIsAnimValItem) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
NS_ENSURE_FINITE(aUserUnitValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
// Although the value passed in is in user units, this method does not turn
|
||||
// this length into a user unit length. Instead it converts the user unit
|
||||
// value to this length's current unit and sets that, leaving this length's
|
||||
// unit as it is.
|
||||
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().SetFromUserUnitValue(aUserUnitValue, Element(), Axis())) {
|
||||
Element()->DidChangeLengthList(mAttrEnum, PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
|
||||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
|
||||
mValue = aUserUnitValue;
|
||||
return NS_OK;
|
||||
}
|
||||
// else [SVGWG issue] Can't convert user unit value to this length's unit
|
||||
// ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::GetValueInSpecifiedUnits(float* aValue)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimValItem && HasOwner()) {
|
||||
Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
|
||||
}
|
||||
#endif
|
||||
*aValue = HasOwner() ? InternalItem().GetValueInCurrentUnits() : mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
|
||||
{
|
||||
if (mIsAnimValItem) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (HasOwner()) {
|
||||
InternalItem().SetValueInCurrentUnits(aValue);
|
||||
Element()->DidChangeLengthList(mAttrEnum, PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
mValue = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::SetValueAsString(const nsAString& aValue)
|
||||
{
|
||||
if (mIsAnimValItem) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
SVGLength value;
|
||||
if (!value.SetValueFromString(aValue)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
InternalItem() = value;
|
||||
Element()->DidChangeLengthList(mAttrEnum, PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
mValue = value.GetValueInCurrentUnits();
|
||||
mUnit = value.GetUnit();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::GetValueAsString(nsAString& aValue)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimValItem && HasOwner()) {
|
||||
Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
|
||||
}
|
||||
#endif
|
||||
if (HasOwner()) {
|
||||
InternalItem().GetValueAsString(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
SVGLength(mValue, mUnit).GetValueAsString(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::NewValueSpecifiedUnits(PRUint16 aUnit, float aValue)
|
||||
{
|
||||
if (mIsAnimValItem) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (!SVGLength::IsValidUnitType(aUnit)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
InternalItem().SetValueAndUnit(aValue, aUnit);
|
||||
Element()->DidChangeLengthList(mAttrEnum, PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mList->mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
mUnit = PRUint8(aUnit);
|
||||
mValue = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLength::ConvertToSpecifiedUnits(PRUint16 aUnit)
|
||||
{
|
||||
if (mIsAnimValItem) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
if (!SVGLength::IsValidUnitType(aUnit)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
if (HasOwner()) {
|
||||
if (InternalItem().ConvertToUnit(PRUint8(aUnit), Element(), Axis())) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
SVGLength len(mValue, mUnit);
|
||||
if (len.ConvertToUnit(PRUint8(aUnit), nsnull, 0)) {
|
||||
mValue = len.GetValueInCurrentUnits();
|
||||
mUnit = aUnit;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// else [SVGWG issue] Can't convert unit
|
||||
// ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGLength::InsertingIntoList(DOMSVGLengthList *aList,
|
||||
PRUint32 aAttrEnum,
|
||||
PRUint8 aListIndex,
|
||||
PRUint8 aIsAnimValItem)
|
||||
{
|
||||
NS_ASSERTION(!HasOwner(), "Inserting item that is already in a list");
|
||||
NS_ASSERTION(mIsAnimValItem &&
|
||||
aListIndex < aList->Element()->GetAnimatedLengthList(aAttrEnum)->GetAnimValue().Length() ||
|
||||
!aIsAnimValItem &&
|
||||
aListIndex < aList->Element()->GetAnimatedLengthList(aAttrEnum)->GetBaseValue().Length(),
|
||||
"mListIndex too big");
|
||||
|
||||
mList = aList;
|
||||
mAttrEnum = aAttrEnum;
|
||||
mListIndex = aListIndex;
|
||||
mIsAnimValItem = aIsAnimValItem;
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGLength::RemovingFromList()
|
||||
{
|
||||
mValue = InternalItem().GetValueInCurrentUnits();
|
||||
mUnit = InternalItem().GetUnit();
|
||||
mList = nsnull;
|
||||
mIsAnimValItem = 0;
|
||||
}
|
||||
|
||||
SVGLength
|
||||
DOMSVGLength::ToSVGLength()
|
||||
{
|
||||
if (HasOwner()) {
|
||||
return SVGLength(InternalItem().GetValueInCurrentUnits(),
|
||||
InternalItem().GetUnit());
|
||||
}
|
||||
return SVGLength(mValue, mUnit);
|
||||
}
|
||||
|
||||
SVGLength&
|
||||
DOMSVGLength::InternalItem()
|
||||
{
|
||||
SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(mAttrEnum);
|
||||
return mIsAnimValItem && alist->mAnimVal ?
|
||||
(*alist->mAnimVal)[mListIndex] :
|
||||
alist->mBaseVal[mListIndex];
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,226 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_DOMSVGLENGTH_H__
|
||||
#define MOZILLA_DOMSVGLENGTH_H__
|
||||
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "DOMSVGLengthList.h"
|
||||
#include "SVGLength.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
// We make DOMSVGLength a pseudo-interface to allow us to QI to it in order to
|
||||
// check that the objects that scripts pass to DOMSVGLengthList methods are our
|
||||
// *native* length objects.
|
||||
//
|
||||
// {A8468350-7F7B-4976-9A7E-3765A1DADF9A}
|
||||
#define MOZILLA_DOMSVGLENGTH_IID \
|
||||
{ 0xA8468350, 0x7F7B, 0x4976, { 0x9A, 0x7E, 0x37, 0x65, 0xA1, 0xDA, 0xDF, 0x9A } }
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Class DOMSVGLength
|
||||
*
|
||||
* This class creates the DOM objects that wrap internal SVGLength objects that
|
||||
* are in an SVGLengthList. It is also used to create the objects returned by
|
||||
* SVGSVGElement.createSVGLength().
|
||||
*
|
||||
* For the DOM wrapper classes for non-list SVGLength, see nsSVGLength2.h.
|
||||
*
|
||||
* See the architecture comment in DOMSVGAnimatedLengthList.h.
|
||||
*
|
||||
* This class is strongly intertwined with DOMSVGAnimatedLengthList and
|
||||
* DOMSVGLengthList. We are a friend of DOMSVGLengthList, and are responsible
|
||||
* for nulling out our DOMSVGLengthList's pointer to us when we die, making it
|
||||
* a real weak pointer.
|
||||
*
|
||||
* When objects of this type are in a DOMSVGLengthList they belong to an
|
||||
* attribute. While they belong to an attribute, the objects' values come from
|
||||
* their corresponding internal SVGLength objects in the internal SVGLengthList
|
||||
* objects for the attribute. Getting and setting values of a DOMSVGLength
|
||||
* requires reading and writing to its internal SVGLength. However, if the
|
||||
* DOMSVGLength is detached from its DOMSVGLengthList then it first makes a
|
||||
* copy of its internal SVGLength's value and unit so that it doesn't appear to
|
||||
* "lose" its value from script's perspective on being removed from the list.
|
||||
* This means that these DOM tearoffs have space to store these values, even
|
||||
* though they're not used in the common case.
|
||||
*
|
||||
* This class also stores its current list index, attribute enum, and whether
|
||||
* it belongs to a baseVal or animVal list. This is so that objects of this
|
||||
* type can find their corresponding internal SVGLength.
|
||||
*
|
||||
* To use these classes for <length> attributes as well as <list-of-length>
|
||||
* attributes, we would need to take a bit from mListIndex and use that to
|
||||
* indicate whether the object belongs to a list or non-list attribute, then
|
||||
* if-else as appropriate. The bug for doing that work is:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=571734
|
||||
*/
|
||||
class DOMSVGLength : public nsIDOMSVGLength
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGLENGTH_IID)
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGLength)
|
||||
NS_DECL_NSIDOMSVGLENGTH
|
||||
|
||||
/**
|
||||
* Generic ctor for DOMSVGLength objects that are created for an attribute.
|
||||
*/
|
||||
DOMSVGLength(DOMSVGLengthList *aList,
|
||||
PRUint32 aAttrEnum,
|
||||
PRUint8 aListIndex,
|
||||
PRUint8 aIsAnimValItem);
|
||||
|
||||
/**
|
||||
* Ctor for creating the objects returned by SVGSVGElement.createSVGLength(),
|
||||
* which do not initially belong to an attribute.
|
||||
*/
|
||||
DOMSVGLength();
|
||||
|
||||
~DOMSVGLength() {
|
||||
// Our mList's weak ref to us must be nulled out when we die. If GC has
|
||||
// unlinked us using the cycle collector code, then that has already
|
||||
// happened, and mList is null.
|
||||
if (mList) {
|
||||
mList->mItems[mListIndex] = nsnull;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an unowned copy of an owned length. The caller is responsible for
|
||||
* the first AddRef().
|
||||
*/
|
||||
DOMSVGLength* Copy() {
|
||||
NS_ASSERTION(mList, "unexpected caller");
|
||||
DOMSVGLength *copy = new DOMSVGLength();
|
||||
SVGLength &length = InternalItem();
|
||||
copy->NewValueSpecifiedUnits(length.GetUnit(), length.GetValueInCurrentUnits());
|
||||
return copy;
|
||||
}
|
||||
|
||||
PRBool IsInList() const {
|
||||
return !!mList;
|
||||
}
|
||||
|
||||
/**
|
||||
* In future, if this class is used for non-list lengths, this will be
|
||||
* different to IsInList().
|
||||
*/
|
||||
PRBool HasOwner() const {
|
||||
return !!mList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to notify this DOM object that it is being inserted
|
||||
* into a list, and give it the information it needs as a result.
|
||||
*
|
||||
* This object MUST NOT already belong to a list when this method is called.
|
||||
* That's not to say that script can't move these DOM objects between
|
||||
* lists - it can - it's just that the logic to handle that (and send out
|
||||
* the necessary notifications) is located elsewhere (in DOMSVGLengthList).)
|
||||
*/
|
||||
void InsertingIntoList(DOMSVGLengthList *aList,
|
||||
PRUint32 aAttrEnum,
|
||||
PRUint8 aListIndex,
|
||||
PRUint8 aIsAnimValItem);
|
||||
|
||||
/// This method is called to notify this object that its list index changed.
|
||||
void UpdateListIndex(PRUint8 aListIndex) {
|
||||
mListIndex = aListIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to notify this DOM object that it is about to be
|
||||
* removed from its current DOM list so that it can first make a copy of its
|
||||
* internal counterpart's values. (If it didn't do this, then it would
|
||||
* "loose" its value on being removed.)
|
||||
*/
|
||||
void RemovingFromList();
|
||||
|
||||
SVGLength ToSVGLength();
|
||||
|
||||
private:
|
||||
|
||||
nsSVGElement* Element() {
|
||||
return mList->Element();
|
||||
}
|
||||
|
||||
PRUint8 AttrEnum() const {
|
||||
return mAttrEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the axis that this length lies along. This method must only be called
|
||||
* when this object is associated with an element (HasOwner() returns true).
|
||||
*/
|
||||
PRUint8 Axis() const {
|
||||
return mList->Axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the internal SVGLength list item that this DOM wrapper
|
||||
* object currently wraps.
|
||||
*
|
||||
* To simplyfy the code we just have this one method for obtaining both
|
||||
* baseVal and animVal internal items. This means that animVal items don't
|
||||
* get const protection, but then our setter methods guard against changing
|
||||
* animVal items.
|
||||
*/
|
||||
SVGLength& InternalItem();
|
||||
|
||||
nsRefPtr<DOMSVGLengthList> mList;
|
||||
|
||||
// Bounds for the following are checked in the ctor, so be sure to update
|
||||
// that if you change the capacity of any of the following.
|
||||
|
||||
PRUint32 mListIndex:22; // supports > 4 million list items
|
||||
PRUint32 mAttrEnum:4; // supports up to 16 attributes
|
||||
PRUint32 mIsAnimValItem:1;
|
||||
|
||||
// The following members are only used when we're not in a list:
|
||||
PRUint32 mUnit:5; // can handle 31 units (the 10 SVG 1.1 units + rem, vw, vh, wm, calc + future additions)
|
||||
float mValue;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGLength, MOZILLA_DOMSVGLENGTH_IID)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DOMSVGLENGTH_H__
|
|
@ -0,0 +1,329 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsSVGElement.h"
|
||||
#include "DOMSVGLengthList.h"
|
||||
#include "DOMSVGLength.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// See the comment in this file's header.
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
|
||||
// clear our DOMSVGAnimatedLengthList's weak ref to us to be safe. (The other
|
||||
// option would be to not unlink and rely on the breaking of the other edges in
|
||||
// the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLengthList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLengthList)
|
||||
// No need to null check tmp - script/SMIL can't detach us from mAList
|
||||
( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) = nsnull;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLengthList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGLengthList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGLengthList)
|
||||
|
||||
}
|
||||
DOMCI_DATA(SVGLengthList, DOMSVGLengthList)
|
||||
namespace mozilla {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
void
|
||||
DOMSVGLengthList::InternalListLengthWillChange(PRUint32 aNewLength)
|
||||
{
|
||||
PRUint32 oldLength = mItems.Length();
|
||||
|
||||
// If our length will decrease, notify the items that will be removed:
|
||||
for (PRUint32 i = aNewLength; i < oldLength; ++i) {
|
||||
if (mItems[i]) {
|
||||
mItems[i]->RemovingFromList();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mItems.SetLength(aNewLength)) { // OOM
|
||||
mItems.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// If our length has increased, null out the new pointers:
|
||||
for (PRUint32 i = oldLength; i < aNewLength; ++i) {
|
||||
mItems[i] = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
SVGLengthList&
|
||||
DOMSVGLengthList::InternalList()
|
||||
{
|
||||
SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(AttrEnum());
|
||||
return IsAnimValList() && alist->mAnimVal ? *alist->mAnimVal : alist->mBaseVal;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// nsIDOMSVGLengthList implementation:
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::GetNumberOfItems(PRUint32 *aNumberOfItems)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (IsAnimValList()) {
|
||||
Element()->FlushAnimations();
|
||||
}
|
||||
#endif
|
||||
*aNumberOfItems = Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::Clear()
|
||||
{
|
||||
if (IsAnimValList()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
if (Length() > 0) {
|
||||
// Notify any existing DOM items of removal *before* truncating the lists
|
||||
// so that they can find their SVGLength internal counterparts and copy
|
||||
// their values:
|
||||
mAList->InternalBaseValListWillChangeTo(SVGLengthList());
|
||||
|
||||
mItems.Clear();
|
||||
InternalList().Clear();
|
||||
Element()->DidChangeLengthList(AttrEnum(), PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::Initialize(nsIDOMSVGLength *newItem,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
*_retval = nsnull;
|
||||
if (IsAnimValList()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
// If newItem is already in a list we should insert a clone of newItem, and
|
||||
// for consistency, this should happen even if *this* is the list that
|
||||
// newItem is currently in. Note that in the case of newItem being in this
|
||||
// list, the Clear() call before the InsertItemBefore() call would remove it
|
||||
// from this list, and so the InsertItemBefore() call would not insert a
|
||||
// clone of newItem, it would actually insert newItem. To prevent that from
|
||||
// happening we have to do the clone here, if necessary.
|
||||
|
||||
nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
|
||||
if (!domItem) {
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
}
|
||||
if (domItem->HasOwner()) {
|
||||
newItem = domItem->Copy();
|
||||
}
|
||||
|
||||
Clear();
|
||||
return InsertItemBefore(newItem, 0, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::GetItem(PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
if (IsAnimValList()) {
|
||||
Element()->FlushAnimations();
|
||||
}
|
||||
#endif
|
||||
if (index < Length()) {
|
||||
EnsureItemAt(index);
|
||||
NS_ADDREF(*_retval = mItems[index]);
|
||||
return NS_OK;
|
||||
}
|
||||
*_retval = nsnull;
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
|
||||
PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
*_retval = nsnull;
|
||||
if (IsAnimValList()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
|
||||
if (!domItem) {
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
}
|
||||
index = NS_MIN(index, Length());
|
||||
SVGLength length = domItem->ToSVGLength(); // get before setting domItem
|
||||
if (domItem->HasOwner()) {
|
||||
domItem = new DOMSVGLength();
|
||||
}
|
||||
PRBool ok = !!InternalList().InsertItem(index, length);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
|
||||
ok = !!mItems.InsertElementAt(index, domItem.get());
|
||||
if (!ok) {
|
||||
InternalList().RemoveItem(index);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
for (PRUint32 i = index + 1; i < Length(); ++i) {
|
||||
if (mItems[i]) {
|
||||
mItems[i]->UpdateListIndex(i);
|
||||
}
|
||||
}
|
||||
Element()->DidChangeLengthList(AttrEnum(), PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
*_retval = domItem.forget().get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
|
||||
PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
*_retval = nsnull;
|
||||
if (IsAnimValList()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
|
||||
if (!domItem) {
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
}
|
||||
if (index >= Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
SVGLength length = domItem->ToSVGLength(); // get before setting domItem
|
||||
if (domItem->HasOwner()) {
|
||||
domItem = new DOMSVGLength();
|
||||
}
|
||||
if (mItems[index]) {
|
||||
// Notify any existing DOM item of removal *before* modifying the lists so
|
||||
// that the DOM item can copy the *old* value at its index:
|
||||
mItems[index]->RemovingFromList();
|
||||
}
|
||||
InternalList()[index] = length;
|
||||
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
|
||||
mItems[index] = domItem;
|
||||
|
||||
Element()->DidChangeLengthList(AttrEnum(), PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
NS_ADDREF(*_retval = domItem.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::RemoveItem(PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
*_retval = nsnull;
|
||||
if (IsAnimValList()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
if (index >= Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
// We have to return the removed item, so make sure it exists:
|
||||
EnsureItemAt(index);
|
||||
|
||||
// Notify the DOM item of removal *before* modifying the lists so that the
|
||||
// DOM item can copy its *old* value:
|
||||
mItems[index]->RemovingFromList();
|
||||
|
||||
InternalList().RemoveItem(index);
|
||||
|
||||
NS_ADDREF(*_retval = mItems[index]);
|
||||
mItems.RemoveElementAt(index);
|
||||
for (PRUint32 i = index; i < Length(); ++i) {
|
||||
if (mItems[i]) {
|
||||
mItems[i]->UpdateListIndex(i);
|
||||
}
|
||||
}
|
||||
Element()->DidChangeLengthList(AttrEnum(), PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mAList->IsAnimating()) {
|
||||
Element()->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMSVGLengthList::AppendItem(nsIDOMSVGLength *newItem,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
return InsertItemBefore(newItem, Length(), _retval);
|
||||
}
|
||||
|
||||
void
|
||||
DOMSVGLengthList::EnsureItemAt(PRUint32 aIndex)
|
||||
{
|
||||
if (!mItems[aIndex]) {
|
||||
mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,157 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_DOMSVGLENGTHLIST_H__
|
||||
#define MOZILLA_DOMSVGLENGTHLIST_H__
|
||||
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "SVGLength.h"
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class DOMSVGLength;
|
||||
|
||||
/**
|
||||
* Class DOMSVGLengthList
|
||||
*
|
||||
* This class is used to create the DOM tearoff objects that wrap internal
|
||||
* SVGLengthList objects.
|
||||
*
|
||||
* See the architecture comment in DOMSVGAnimatedLengthList.h.
|
||||
*
|
||||
* This class is strongly intertwined with DOMSVGAnimatedLengthList and
|
||||
* DOMSVGLength. We are a friend of DOMSVGAnimatedLengthList, and are
|
||||
* responsible for nulling out our DOMSVGAnimatedLengthList's pointer to us
|
||||
* when we die, essentially making its pointer to us a weak pointer. Similarly,
|
||||
* our DOMSVGLength items are friends of us and responsible for nulling out our
|
||||
* pointers to them.
|
||||
*
|
||||
* Our DOM items are created lazily on demand as and when script requests them.
|
||||
*/
|
||||
class DOMSVGLengthList : public nsIDOMSVGLengthList
|
||||
{
|
||||
friend class DOMSVGLength;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGLengthList)
|
||||
NS_DECL_NSIDOMSVGLENGTHLIST
|
||||
|
||||
DOMSVGLengthList(DOMSVGAnimatedLengthList *aAList)
|
||||
: mAList(aAList)
|
||||
{
|
||||
// We silently ignore SetLength OOM failure since being out of sync is safe
|
||||
// so long as we have *fewer* items than our internal list.
|
||||
|
||||
mItems.SetLength(InternalList().Length());
|
||||
for (PRUint32 i = 0; i < Length(); ++i) {
|
||||
// null out all the pointers - items are created on-demand
|
||||
mItems[i] = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
~DOMSVGLengthList() {
|
||||
// Our mAList's weak ref to us must be nulled out when we die. If GC has
|
||||
// unlinked us using the cycle collector code, then that has already
|
||||
// happened, and mAList is null.
|
||||
if (mAList) {
|
||||
( IsAnimValList() ? mAList->mAnimVal : mAList->mBaseVal ) = nsnull;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This will normally be the same as InternalList().Length(), except if we've
|
||||
* hit OOM in which case our length will be zero.
|
||||
*/
|
||||
PRUint32 Length() const {
|
||||
NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
|
||||
mItems.Length() ==
|
||||
const_cast<DOMSVGLengthList*>(this)->InternalList().Length(),
|
||||
"DOM wrapper's list length is out of sync");
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
/// Called to notify us to syncronize our length and detach excess items.
|
||||
void InternalListLengthWillChange(PRUint32 aNewLength);
|
||||
|
||||
private:
|
||||
|
||||
nsSVGElement* Element() {
|
||||
return mAList->mElement;
|
||||
}
|
||||
|
||||
PRUint8 AttrEnum() const {
|
||||
return mAList->mAttrEnum;
|
||||
}
|
||||
|
||||
PRUint8 Axis() const {
|
||||
return mAList->mAxis;
|
||||
}
|
||||
|
||||
/// Used to determine if this list is the baseVal or animVal list.
|
||||
PRBool IsAnimValList() const {
|
||||
return this == mAList->mAnimVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to this object's corresponding internal SVGLengthList.
|
||||
*
|
||||
* To simplyfy the code we just have this one method for obtaining both
|
||||
* baseVal and animVal internal lists. This means that animVal lists don't
|
||||
* get const protection, but our setter methods guard against changing
|
||||
* animVal lists.
|
||||
*/
|
||||
SVGLengthList& InternalList();
|
||||
|
||||
/// Creates a DOMSVGLength for aIndex, if it doesn't already exist.
|
||||
void EnsureItemAt(PRUint32 aIndex);
|
||||
|
||||
// Weak refs to our DOMSVGLength items. The items are friends and take care
|
||||
// of clearing our pointer to them when they die.
|
||||
nsTArray<DOMSVGLength*> mItems;
|
||||
|
||||
nsRefPtr<DOMSVGAnimatedLengthList> mAList;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DOMSVGLENGTHLIST_H__
|
|
@ -49,12 +49,14 @@ LIBRARY_NAME = gkcontentsvg_s
|
|||
LIBXUL_LIBRARY = 1
|
||||
|
||||
CPPSRCS = \
|
||||
DOMSVGAnimatedLengthList.cpp \
|
||||
DOMSVGLength.cpp \
|
||||
DOMSVGLengthList.cpp \
|
||||
nsDOMSVGZoomEvent.cpp \
|
||||
nsDOMSVGEvent.cpp \
|
||||
nsSVGAElement.cpp \
|
||||
nsSVGAltGlyphElement.cpp \
|
||||
nsSVGAngle.cpp \
|
||||
nsSVGAnimatedLengthList.cpp \
|
||||
nsSVGAnimatedNumberList.cpp \
|
||||
nsSVGAnimatedTransformList.cpp \
|
||||
nsSVGBoolean.cpp \
|
||||
|
@ -76,9 +78,7 @@ CPPSRCS = \
|
|||
nsSVGGraphicElement.cpp \
|
||||
nsSVGImageElement.cpp \
|
||||
nsSVGInteger.cpp \
|
||||
nsSVGLength.cpp \
|
||||
nsSVGLength2.cpp \
|
||||
nsSVGLengthList.cpp \
|
||||
nsSVGLineElement.cpp \
|
||||
nsSVGMarkerElement.cpp \
|
||||
nsSVGMaskElement.cpp \
|
||||
|
@ -122,6 +122,9 @@ CPPSRCS = \
|
|||
nsSVGUseElement.cpp \
|
||||
nsSVGValue.cpp \
|
||||
nsSVGViewBox.cpp \
|
||||
SVGAnimatedLengthList.cpp \
|
||||
SVGLength.cpp \
|
||||
SVGLengthList.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_SMIL
|
||||
|
@ -133,6 +136,7 @@ CPPSRCS += nsSVGAnimateElement.cpp \
|
|||
nsSVGSetElement.cpp \
|
||||
nsSVGTransformSMILType.cpp \
|
||||
nsSVGTransformSMILAttr.cpp \
|
||||
SVGLengthListSMILType.cpp \
|
||||
SVGMotionSMILType.cpp \
|
||||
SVGMotionSMILAttr.cpp \
|
||||
SVGMotionSMILAnimationFunction.cpp \
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsSVGAttrTearoffTable.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGLengthListSMILType.h"
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
SVGAnimatedLengthList::SetBaseValueString(const nsAString& aValue)
|
||||
{
|
||||
SVGLengthList newBaseValue;
|
||||
nsresult rv = newBaseValue.SetValueFromString(aValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DOMSVGAnimatedLengthList *domWrapper =
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(this);
|
||||
if (domWrapper) {
|
||||
// We must send this notification *before* changing mBaseVal! If the length
|
||||
// of our baseVal is being reduced, our baseVal's DOM wrapper list may have
|
||||
// to remove DOM items from itself, and any removed DOM items need to copy
|
||||
// their internal counterpart values *before* we change them.
|
||||
//
|
||||
domWrapper->InternalBaseValListWillChangeTo(newBaseValue);
|
||||
}
|
||||
|
||||
// We don't need to call DidChange* here - we're only called by
|
||||
// nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
|
||||
// which takes care of notifying.
|
||||
|
||||
rv = mBaseVal.CopyFrom(newBaseValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Attempting to increase mBaseVal's length failed - reduce domWrapper
|
||||
// back to the same length:
|
||||
domWrapper->InternalBaseValListWillChangeTo(mBaseVal);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
SVGAnimatedLengthList::ClearBaseValue(PRUint32 aAttrEnum)
|
||||
{
|
||||
DOMSVGAnimatedLengthList *domWrapper =
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(this);
|
||||
if (domWrapper) {
|
||||
// We must send this notification *before* changing mBaseVal! (See above.)
|
||||
domWrapper->InternalAnimValListWillChangeTo(SVGLengthList());
|
||||
}
|
||||
mBaseVal.Clear();
|
||||
// Caller notifies
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedLengthList::SetAnimValue(const SVGLengthList& aNewAnimValue,
|
||||
nsSVGElement *aElement,
|
||||
PRUint32 aAttrEnum)
|
||||
{
|
||||
DOMSVGAnimatedLengthList *domWrapper =
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(this);
|
||||
if (domWrapper) {
|
||||
// A new animation may totally change the number of items in the animVal
|
||||
// list, replacing what was essentially a mirror of the baseVal list, or
|
||||
// else replacing and overriding an existing animation. When this happens
|
||||
// we must try and keep our animVal's DOM wrapper in sync (see the comment
|
||||
// in DOMSVGAnimatedLengthList::InternalBaseValListWillChangeTo).
|
||||
//
|
||||
// It's not possible for us to reliably distinguish between calls to this
|
||||
// method that are setting a new sample for an existing animation, and
|
||||
// calls that are setting the first sample of an animation that will
|
||||
// override an existing animation. Happily it's cheap to just blindly
|
||||
// notify our animVal's DOM wrapper of its internal counterpart's new value
|
||||
// each time this method is called, so that's what we do.
|
||||
//
|
||||
// Note that we must send this notification *before* setting or changing
|
||||
// mAnimVal! (See the comment in SetBaseValueString above.)
|
||||
//
|
||||
domWrapper->InternalAnimValListWillChangeTo(aNewAnimValue);
|
||||
}
|
||||
if (!mAnimVal) {
|
||||
mAnimVal = new SVGLengthList();
|
||||
}
|
||||
nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
// OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
|
||||
// that mAnimVal and its DOM wrapper (if any) will have the same length!
|
||||
ClearAnimValue(aElement, aAttrEnum);
|
||||
return rv;
|
||||
}
|
||||
aElement->DidAnimateLengthList(aAttrEnum);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SVGAnimatedLengthList::ClearAnimValue(nsSVGElement *aElement,
|
||||
PRUint32 aAttrEnum)
|
||||
{
|
||||
DOMSVGAnimatedLengthList *domWrapper =
|
||||
DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(this);
|
||||
if (domWrapper) {
|
||||
// When all animation ends, animVal simply mirrors baseVal, which may have
|
||||
// a different number of items to the last active animated value. We must
|
||||
// keep the length of our animVal's DOM wrapper list in sync, and again we
|
||||
// must do that before touching mAnimVal. See comments above.
|
||||
//
|
||||
domWrapper->InternalAnimValListWillChangeTo(mBaseVal);
|
||||
}
|
||||
mAnimVal = nsnull;
|
||||
aElement->DidAnimateLengthList(aAttrEnum);
|
||||
}
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
nsISMILAttr*
|
||||
SVGAnimatedLengthList::ToSMILAttr(nsSVGElement *aSVGElement,
|
||||
PRUint8 aAttrEnum,
|
||||
PRUint8 aAxis,
|
||||
PRBool aCanZeroPadList)
|
||||
{
|
||||
return new SMILAnimatedLengthList(this, aSVGElement, aAttrEnum, aAxis, aCanZeroPadList);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedLengthList::
|
||||
SMILAnimatedLengthList::ValueFromString(const nsAString& aStr,
|
||||
const nsISMILAnimationElement* /*aSrcElement*/,
|
||||
nsSMILValue& aValue,
|
||||
PRBool& aPreventCachingOfSandwich) const
|
||||
{
|
||||
nsSMILValue val(&SVGLengthListSMILType::sSingleton);
|
||||
SVGLengthListAndInfo *llai = static_cast<SVGLengthListAndInfo*>(val.mU.mPtr);
|
||||
nsresult rv = llai->SetValueFromString(aStr);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
llai->SetInfo(mElement, mAxis, mCanZeroPadList);
|
||||
aValue.Swap(val);
|
||||
|
||||
// If any of the lengths in the list depend on their context, then we must
|
||||
// prevent caching of the entire animation sandwich. This is because the
|
||||
// units of a length at a given index can change from sandwich layer to
|
||||
// layer, and indeed even be different within a single sandwich layer. If
|
||||
// any length in the result of an animation sandwich is the result of the
|
||||
// addition of lengths where one or more of those lengths is context
|
||||
// dependent, then naturally the resultant length is also context
|
||||
// dependent, regardless of whether its actual unit is context dependent or
|
||||
// not. Unfortunately normal invalidation mechanisms won't cause us to
|
||||
// recalculate the result of the sandwich if the context changes, so we
|
||||
// take the (substantial) performance hit of preventing caching of the
|
||||
// sandwich layer, causing the animation sandwich to be recalculated every
|
||||
// single sample.
|
||||
|
||||
aPreventCachingOfSandwich = PR_FALSE;
|
||||
for (PRUint32 i = 0; i < llai->Length(); ++i) {
|
||||
PRUint8 unit = (*llai)[i].GetUnit();
|
||||
if (unit == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE ||
|
||||
unit == nsIDOMSVGLength::SVG_LENGTHTYPE_EMS ||
|
||||
unit == nsIDOMSVGLength::SVG_LENGTHTYPE_EXS) {
|
||||
aPreventCachingOfSandwich = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsSMILValue
|
||||
SVGAnimatedLengthList::SMILAnimatedLengthList::GetBaseValue() const
|
||||
{
|
||||
// To benefit from Return Value Optimization and avoid copy constructor calls
|
||||
// due to our use of return-by-value, we must return the exact same object
|
||||
// from ALL return points. This function must only return THIS variable:
|
||||
nsSMILValue val;
|
||||
|
||||
nsSMILValue tmp(&SVGLengthListSMILType::sSingleton);
|
||||
SVGLengthListAndInfo *llai = static_cast<SVGLengthListAndInfo*>(tmp.mU.mPtr);
|
||||
nsresult rv = llai->CopyFrom(mVal->mBaseVal);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
llai->SetInfo(mElement, mAxis, mCanZeroPadList);
|
||||
val.Swap(tmp);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGAnimatedLengthList::SMILAnimatedLengthList::SetAnimValue(const nsSMILValue& aValue)
|
||||
{
|
||||
NS_ASSERTION(aValue.mType == &SVGLengthListSMILType::sSingleton,
|
||||
"Unexpected type to assign animated value");
|
||||
if (aValue.mType == &SVGLengthListSMILType::sSingleton) {
|
||||
mVal->SetAnimValue(*static_cast<SVGLengthListAndInfo*>(aValue.mU.mPtr),
|
||||
mElement,
|
||||
mAttrEnum);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SVGAnimatedLengthList::SMILAnimatedLengthList::ClearAnimValue()
|
||||
{
|
||||
if (mVal->mAnimVal) {
|
||||
mVal->ClearAnimValue(mElement, mAttrEnum);
|
||||
}
|
||||
}
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_SVGANIMATEDLENGTHLIST_H__
|
||||
#define MOZILLA_SVGANIMATEDLENGTHLIST_H__
|
||||
|
||||
#include "SVGLengthList.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsISMILAttr.h"
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Class SVGAnimatedLengthList
|
||||
*
|
||||
* This class is very different to the SVG DOM interface of the same name found
|
||||
* in the SVG specification. This is a lightweight internal class - see
|
||||
* DOMSVGAnimatedLengthList for the heavier DOM class that wraps instances of
|
||||
* this class and implements the SVG specification's SVGAnimatedLengthList DOM
|
||||
* interface.
|
||||
*
|
||||
* Except where noted otherwise, this class' methods take care of keeping the
|
||||
* appropriate DOM wrappers in sync (see the comment in
|
||||
* DOMSVGAnimatedLengthList::InternalBaseValListWillChangeTo) so that their
|
||||
* consumers don't need to concern themselves with that.
|
||||
*/
|
||||
class SVGAnimatedLengthList
|
||||
{
|
||||
// friends so that they can get write access to mBaseVal
|
||||
friend class DOMSVGLength;
|
||||
friend class DOMSVGLengthList;
|
||||
|
||||
public:
|
||||
SVGAnimatedLengthList() {}
|
||||
|
||||
/**
|
||||
* Because it's so important that mBaseVal and its DOMSVGLengthList wrapper
|
||||
* (if any) be kept in sync (see the comment in
|
||||
* DOMSVGAnimatedLengthList::InternalBaseValListWillChangeTo), this method
|
||||
* returns a const reference. Only our friend classes may get mutable
|
||||
* references to mBaseVal.
|
||||
*/
|
||||
const SVGLengthList& GetBaseValue() const {
|
||||
return mBaseVal;
|
||||
}
|
||||
|
||||
nsresult SetBaseValueString(const nsAString& aValue);
|
||||
|
||||
void ClearBaseValue(PRUint32 aAttrEnum);
|
||||
|
||||
const SVGLengthList& GetAnimValue() const {
|
||||
return mAnimVal ? *mAnimVal : mBaseVal;
|
||||
}
|
||||
|
||||
nsresult SetAnimValue(const SVGLengthList& aValue,
|
||||
nsSVGElement *aElement,
|
||||
PRUint32 aAttrEnum);
|
||||
|
||||
void ClearAnimValue(nsSVGElement *aElement,
|
||||
PRUint32 aAttrEnum);
|
||||
|
||||
PRBool IsAnimating() const {
|
||||
return !!mAnimVal;
|
||||
}
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
/// Callers own the returned nsISMILAttr
|
||||
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement, PRUint8 aAttrEnum,
|
||||
PRUint8 aAxis, PRBool aCanZeroPadList);
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
private:
|
||||
|
||||
// mAnimVal is a pointer to allow us to determine if we're being animated or
|
||||
// not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
|
||||
// if we're animating is not an option, since that would break animation *to*
|
||||
// the empty string (<set to="">).
|
||||
|
||||
SVGLengthList mBaseVal;
|
||||
nsAutoPtr<SVGLengthList> mAnimVal;
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
struct SMILAnimatedLengthList : public nsISMILAttr
|
||||
{
|
||||
public:
|
||||
SMILAnimatedLengthList(SVGAnimatedLengthList* aVal,
|
||||
nsSVGElement* aSVGElement,
|
||||
PRUint8 aAttrEnum,
|
||||
PRUint8 aAxis,
|
||||
PRBool aCanZeroPadList)
|
||||
: mVal(aVal)
|
||||
, mElement(aSVGElement)
|
||||
, mAttrEnum(aAttrEnum)
|
||||
, mAxis(aAxis)
|
||||
, mCanZeroPadList(aCanZeroPadList)
|
||||
{}
|
||||
|
||||
// These will stay alive because a nsISMILAttr only lives as long
|
||||
// as the Compositing step, and DOM elements don't get a chance to
|
||||
// die during that.
|
||||
SVGAnimatedLengthList* mVal;
|
||||
nsSVGElement* mElement;
|
||||
PRUint8 mAttrEnum;
|
||||
PRUint8 mAxis;
|
||||
PRPackedBool mCanZeroPadList; // See SVGLengthListAndInfo::CanZeroPadList
|
||||
|
||||
// nsISMILAttr methods
|
||||
virtual nsresult ValueFromString(const nsAString& aStr,
|
||||
const nsISMILAnimationElement* aSrcElement,
|
||||
nsSMILValue& aValue,
|
||||
PRBool& aPreventCachingOfSandwich) const;
|
||||
virtual nsSMILValue GetBaseValue() const;
|
||||
virtual void ClearAnimValue();
|
||||
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
|
||||
};
|
||||
#endif // MOZ_SMIL
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_SVGANIMATEDLENGTHLIST_H__
|
|
@ -0,0 +1,295 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "SVGLength.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsSVGSVGElement.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "prdtoa.h"
|
||||
#include <limits>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Declare some helpers defined below:
|
||||
static void GetUnitString(nsAString& unit, PRUint16 unitType);
|
||||
static PRUint16 GetUnitTypeForString(const char* unitStr);
|
||||
|
||||
void
|
||||
SVGLength::GetValueAsString(nsAString &aValue) const
|
||||
{
|
||||
PRUnichar buf[24];
|
||||
nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
|
||||
NS_LITERAL_STRING("%g").get(),
|
||||
(double)mValue);
|
||||
aValue.Assign(buf);
|
||||
|
||||
nsAutoString unitString;
|
||||
GetUnitString(unitString, mUnit);
|
||||
aValue.Append(unitString);
|
||||
}
|
||||
|
||||
PRBool
|
||||
SVGLength::SetValueFromString(const nsAString &aValue)
|
||||
{
|
||||
float tmpValue;
|
||||
PRUint16 tmpUnit;
|
||||
|
||||
NS_ConvertUTF16toUTF8 value(aValue);
|
||||
const char *str = value.get();
|
||||
|
||||
while (*str != '\0' && IsSVGWhitespace(*str)) {
|
||||
++str;
|
||||
}
|
||||
char *unit;
|
||||
tmpValue = float(PR_strtod(str, &unit));
|
||||
if (unit != str && NS_FloatIsFinite(tmpValue)) {
|
||||
char *theRest = unit;
|
||||
if (*unit != '\0' && !IsSVGWhitespace(*unit)) {
|
||||
while (*theRest != '\0' && !IsSVGWhitespace(*theRest)) {
|
||||
++theRest;
|
||||
}
|
||||
nsCAutoString unitStr(unit, theRest - unit);
|
||||
tmpUnit = GetUnitTypeForString(unitStr.get());
|
||||
} else {
|
||||
tmpUnit = nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER;
|
||||
}
|
||||
while (*theRest && IsSVGWhitespace(*theRest)) {
|
||||
++theRest;
|
||||
}
|
||||
if (!*theRest) {
|
||||
mValue = tmpValue;
|
||||
mUnit = tmpUnit;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
inline static PRBool
|
||||
IsAbsoluteUnit(PRUint8 aUnit)
|
||||
{
|
||||
return aUnit >= nsIDOMSVGLength::SVG_LENGTHTYPE_CM &&
|
||||
aUnit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to convert between different CSS absolute units without the need for
|
||||
* an element, which provides more flexibility at the DOM level (and without
|
||||
* the need for an intermediary conversion to user units, which avoids
|
||||
* unnecessary overhead and rounding error).
|
||||
*
|
||||
* Example usage: to find out how many centimeters there are per inch:
|
||||
*
|
||||
* GetAbsUnitsPerAbsUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_CM,
|
||||
* nsIDOMSVGLength::SVG_LENGTHTYPE_IN)
|
||||
*/
|
||||
inline static float GetAbsUnitsPerAbsUnit(PRUint8 aUnits, PRUint8 aPerUnit)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(IsAbsoluteUnit(aUnits), "Not a CSS absolute unit");
|
||||
NS_ABORT_IF_FALSE(IsAbsoluteUnit(aPerUnit), "Not a CSS absolute unit");
|
||||
|
||||
float CSSAbsoluteUnitConversionFactors[5][5] = { // columns: cm, mm, in, pt, pc
|
||||
// cm per...:
|
||||
{ 1.0, 0.1, 2.54, 0.035277777777777778, 0.42333333333333333 },
|
||||
// mm per...:
|
||||
{ 10.0, 1.0, 25.4, 0.35277777777777778, 4.2333333333333333 },
|
||||
// in per...:
|
||||
{ 0.39370078740157481, 0.039370078740157481, 1.0, 0.013888888888888889, 0.16666666666666667 },
|
||||
// pt per...:
|
||||
{ 28.346456692913386, 2.8346456692913386, 72.0, 1.0, 12.0 },
|
||||
// pc per...:
|
||||
{ 2.3622047244094489, 0.23622047244094489, 6.0, 0.083333333333333333, 1.0 }
|
||||
};
|
||||
|
||||
// First absolute unit is SVG_LENGTHTYPE_CM = 6
|
||||
return CSSAbsoluteUnitConversionFactors[aUnits - 6][aPerUnit - 6];
|
||||
}
|
||||
|
||||
float
|
||||
SVGLength::GetValueInSpecifiedUnit(PRUint8 aUnit,
|
||||
const nsSVGElement *aElement,
|
||||
PRUint8 aAxis) const
|
||||
{
|
||||
if (aUnit == mUnit) {
|
||||
return mValue;
|
||||
}
|
||||
if ((aUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER &&
|
||||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) ||
|
||||
(aUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX &&
|
||||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)) {
|
||||
return mValue;
|
||||
}
|
||||
if (IsAbsoluteUnit(aUnit) && IsAbsoluteUnit(mUnit)) {
|
||||
return mValue * GetAbsUnitsPerAbsUnit(aUnit, mUnit);
|
||||
}
|
||||
|
||||
// Otherwise we do a two step convertion via user units. This can only
|
||||
// succeed if aElement is non-null (although that's not sufficent to
|
||||
// guarantee success).
|
||||
|
||||
float userUnitsPerCurrentUnit = GetUserUnitsPerUnit(aElement, aAxis);
|
||||
float userUnitsPerNewUnit =
|
||||
SVGLength(0.0f, aUnit).GetUserUnitsPerUnit(aElement, aAxis);
|
||||
|
||||
NS_ASSERTION(userUnitsPerCurrentUnit >= 0 ||
|
||||
!NS_FloatIsFinite(userUnitsPerCurrentUnit),
|
||||
"bad userUnitsPerCurrentUnit");
|
||||
NS_ASSERTION(userUnitsPerNewUnit >= 0 ||
|
||||
!NS_FloatIsFinite(userUnitsPerNewUnit),
|
||||
"bad userUnitsPerNewUnit");
|
||||
|
||||
float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
|
||||
|
||||
// userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
|
||||
// be zero.
|
||||
if (NS_FloatIsFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
#define INCHES_PER_MM_FLOAT float(0.0393700787)
|
||||
#define INCHES_PER_CM_FLOAT float(0.393700787)
|
||||
|
||||
float
|
||||
SVGLength::GetUserUnitsPerUnit(const nsSVGElement *aElement, PRUint8 aAxis) const
|
||||
{
|
||||
switch (mUnit) {
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
|
||||
return 1.0f;
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
|
||||
return INCHES_PER_MM_FLOAT * GetUserUnitsPerInch(aElement);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
|
||||
return INCHES_PER_CM_FLOAT * GetUserUnitsPerInch(aElement);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
|
||||
return GetUserUnitsPerInch(aElement);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
|
||||
return (1.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch(aElement);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
|
||||
return (12.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch(aElement);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
|
||||
return GetUserUnitsPerPercent(aElement, aAxis);
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
|
||||
return nsSVGUtils::GetFontSize(const_cast<nsSVGElement*>(aElement));
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
|
||||
return nsSVGUtils::GetFontXHeight(const_cast<nsSVGElement*>(aElement));
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit type");
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ float
|
||||
SVGLength::GetUserUnitsPerInch(const nsIContent *aContent)
|
||||
{
|
||||
if (aContent) {
|
||||
nsPresContext *context = nsContentUtils::GetContextForContent(
|
||||
const_cast<nsIContent*>(aContent));
|
||||
if (context) {
|
||||
float uuPerInch = float(context->AppUnitsPerInch()) /
|
||||
float(nsPresContext::AppUnitsPerCSSPixel());
|
||||
NS_ASSERTION(uuPerInch > 0.0f, "Non-positive user units per inch");
|
||||
return uuPerInch;
|
||||
}
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
/* static */ float
|
||||
SVGLength::GetUserUnitsPerPercent(const nsSVGElement *aElement, PRUint8 aAxis)
|
||||
{
|
||||
if (aElement) {
|
||||
nsSVGSVGElement *viewportElement = const_cast<nsSVGElement*>(aElement)->GetCtx();
|
||||
if (viewportElement) {
|
||||
return NS_MAX(viewportElement->GetLength(aAxis) / 100.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
// Helpers:
|
||||
|
||||
// These items must be at the same index as the nsIDOMSVGLength constants!
|
||||
static nsIAtom** const unitMap[] =
|
||||
{
|
||||
nsnull, /* SVG_LENGTHTYPE_UNKNOWN */
|
||||
nsnull, /* SVG_LENGTHTYPE_NUMBER */
|
||||
&nsGkAtoms::percentage,
|
||||
&nsGkAtoms::em,
|
||||
&nsGkAtoms::ex,
|
||||
&nsGkAtoms::px,
|
||||
&nsGkAtoms::cm,
|
||||
&nsGkAtoms::mm,
|
||||
&nsGkAtoms::in,
|
||||
&nsGkAtoms::pt,
|
||||
&nsGkAtoms::pc
|
||||
};
|
||||
|
||||
static void
|
||||
GetUnitString(nsAString& unit, PRUint16 unitType)
|
||||
{
|
||||
if (SVGLength::IsValidUnitType(unitType)) {
|
||||
if (unitMap[unitType]) {
|
||||
(*unitMap[unitType])->ToString(unit);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NS_NOTREACHED("Unknown unit type"); // Someone's using an SVGLength with an invalid unit?
|
||||
return;
|
||||
}
|
||||
|
||||
static PRUint16
|
||||
GetUnitTypeForString(const char* unitStr)
|
||||
{
|
||||
if (!unitStr || *unitStr == '\0')
|
||||
return nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER;
|
||||
|
||||
nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
|
||||
|
||||
for (PRUint32 i = 1 ; i < NS_ARRAY_LENGTH(unitMap) ; i++) {
|
||||
if (unitMap[i] && *unitMap[i] == unitAtom) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
NS_NOTREACHED("Returning unknown unit type");
|
||||
return nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,255 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_SVGLENGTH_H__
|
||||
#define MOZILLA_SVGLENGTH_H__
|
||||
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This SVGLength class is currently used for SVGLength *list* attributes only.
|
||||
* The class that is currently used for <length> attributes is nsSVGLength2.
|
||||
*
|
||||
* The member mUnit should always be valid, but the member mValue may be
|
||||
* numeric_limits<float>::quiet_NaN() under one circumstances (see the comment
|
||||
* in SetValueAndUnit below). Even if mValue is valid, some methods may return
|
||||
* numeric_limits<float>::quiet_NaN() if they involve a unit conversion that
|
||||
* fails - see comments below.
|
||||
*
|
||||
* The DOM wrapper class for this class is DOMSVGLength.
|
||||
*/
|
||||
class SVGLength
|
||||
{
|
||||
public:
|
||||
|
||||
SVGLength()
|
||||
#ifdef DEBUG
|
||||
: mValue(0.0f)
|
||||
, mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN) // caught by IsValid()
|
||||
#endif
|
||||
{}
|
||||
|
||||
SVGLength(float aValue, PRUint8 aUnit)
|
||||
: mValue(aValue)
|
||||
, mUnit(aUnit)
|
||||
{
|
||||
NS_ASSERTION(IsValid(), "Constructed an invalid length");
|
||||
}
|
||||
|
||||
SVGLength(const SVGLength &aOther)
|
||||
: mValue(aOther.mValue)
|
||||
, mUnit(aOther.mUnit)
|
||||
{}
|
||||
|
||||
SVGLength& operator=(const SVGLength &rhs) {
|
||||
mValue = rhs.mValue;
|
||||
mUnit = rhs.mUnit;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PRBool operator==(const SVGLength &rhs) const {
|
||||
return mValue == rhs.mValue && mUnit == rhs.mUnit;
|
||||
}
|
||||
|
||||
void GetValueAsString(nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* This method returns PR_TRUE, unless there was a parse failure, in which
|
||||
* case it returns PR_FALSE (and the length is left unchanged).
|
||||
*/
|
||||
PRBool SetValueFromString(const nsAString& aValue);
|
||||
|
||||
/**
|
||||
* This will usually return a valid, finite number. There is one exception
|
||||
* though - see the comment in SetValueAndUnit().
|
||||
*/
|
||||
float GetValueInCurrentUnits() const {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
PRUint8 GetUnit() const {
|
||||
return mUnit;
|
||||
}
|
||||
|
||||
void SetValueInCurrentUnits(float aValue) {
|
||||
mValue = aValue;
|
||||
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
|
||||
}
|
||||
|
||||
void SetValueAndUnit(float aValue, PRUint8 aUnit) {
|
||||
mValue = aValue;
|
||||
mUnit = aUnit;
|
||||
|
||||
// IsValid() should always be true, with one exception: if
|
||||
// SVGLengthListSMILType has to convert between unit types and the unit
|
||||
// conversion is undefined, it will end up passing in and setting
|
||||
// numeric_limits<float>::quiet_NaN(). Because of that we only check the
|
||||
// unit here, and allow mValue to be invalid. The painting code has to be
|
||||
// able to handle NaN anyway, since conversion to user units may fail in
|
||||
// general.
|
||||
|
||||
NS_ASSERTION(IsValidUnitType(mUnit), "Set invalid SVGLength");
|
||||
}
|
||||
|
||||
/**
|
||||
* If it's not possible to convert this length's value to user units, then
|
||||
* this method will return numeric_limits<float>::quiet_NaN().
|
||||
*/
|
||||
float GetValueInUserUnits(const nsSVGElement *aElement, PRUint8 aAxis) const {
|
||||
return mValue * GetUserUnitsPerUnit(aElement, aAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this length's value, converting the supplied user unit value to this
|
||||
* lengths *current* unit (i.e. leaving the length's unit unchanged).
|
||||
*
|
||||
* This method returns PR_TRUE, unless the user unit value couldn't be
|
||||
* converted to this length's current unit, in which case it returns PR_FALSE
|
||||
* (and the length is left unchanged).
|
||||
*/
|
||||
PRBool SetFromUserUnitValue(float aUserUnitValue,
|
||||
nsSVGElement *aElement,
|
||||
PRUint8 aAxis) {
|
||||
float uuPerUnit = GetUserUnitsPerUnit(aElement, aAxis);
|
||||
float value = aUserUnitValue / uuPerUnit;
|
||||
if (uuPerUnit > 0 && NS_FloatIsFinite(value)) {
|
||||
mValue = value;
|
||||
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this length's value in the units specified.
|
||||
*
|
||||
* This method returns numeric_limits<float>::quiet_NaN() if it is not
|
||||
* possible to convert the value to the specified unit.
|
||||
*/
|
||||
float GetValueInSpecifiedUnit(PRUint8 aUnit,
|
||||
const nsSVGElement *aElement,
|
||||
PRUint8 aAxis) const;
|
||||
|
||||
/**
|
||||
* Convert this length's value to the unit specified.
|
||||
*
|
||||
* This method returns PR_TRUE, unless it isn't possible to convert the
|
||||
* length to the specified unit. In that case the length is left unchanged
|
||||
* and this method returns PR_FALSE.
|
||||
*/
|
||||
PRBool ConvertToUnit(PRUint32 aUnit, nsSVGElement *aElement, PRUint8 aAxis) {
|
||||
float val = GetValueInSpecifiedUnit(aUnit, aElement, aAxis);
|
||||
if (NS_FloatIsFinite(val)) {
|
||||
mValue = val;
|
||||
mUnit = aUnit;
|
||||
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool IsPercentage() const {
|
||||
return mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE;
|
||||
}
|
||||
|
||||
static PRBool IsValidUnitType(PRUint16 unit) {
|
||||
return unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
|
||||
unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool IsValid() const {
|
||||
return NS_FloatIsFinite(mValue) && IsValidUnitType(mUnit);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the number of user units per current unit.
|
||||
*
|
||||
* This method returns numeric_limits<float>::quiet_NaN() if the conversion
|
||||
* factor between the length's current unit and user units is undefined (see
|
||||
* the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent).
|
||||
*/
|
||||
float GetUserUnitsPerUnit(const nsSVGElement *aElement, PRUint8 aAxis) const;
|
||||
|
||||
/**
|
||||
* The conversion factor between user units (CSS px) and a CSS absolute unit
|
||||
* (in this case inches) is the same for all elements in a given document,
|
||||
* except for elements for which the factor is undefined. The conversion
|
||||
* factor is undefined for elements that are not in a document tree, and for
|
||||
* elements in a document tree that don't have a pres context (elements under
|
||||
* a display:none iframe, or elements belonging to a data document (an XHR
|
||||
* response document or a document created via createDocument()).
|
||||
*
|
||||
* This helper acts as the basis for conversion between user units and all
|
||||
* CSS absolute units (the conversion factors between CSS absolute units are
|
||||
* fixed). Inches are chosen as the canonical unit because that's what
|
||||
* pres/device contexts store, so it makes sense for this helper to also work
|
||||
* in those terms to eliminate unnecessary multiplications/divisions that
|
||||
* must then be reversed.
|
||||
*
|
||||
* This function returns a positive value if the conversion factor is
|
||||
* defined, otherwise it returns numeric_limits<float>::quiet_NaN().
|
||||
*/
|
||||
static float GetUserUnitsPerInch(const nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* The conversion factor between user units and percentage units depends on
|
||||
* aElement being non-null, and on aElement having a viewport element
|
||||
* ancestor with only appropriate SVG elements between aElement and that
|
||||
* ancestor. If that's not the case, then the conversion factor is undefined.
|
||||
*
|
||||
* This function returns a non-negative value if the conversion factor is
|
||||
* defined, otherwise it returns numeric_limits<float>::quiet_NaN().
|
||||
*/
|
||||
static float GetUserUnitsPerPercent(const nsSVGElement *aElement, PRUint8 aAxis);
|
||||
|
||||
float mValue;
|
||||
PRUint8 mUnit;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_SVGLENGTH_H__
|
|
@ -0,0 +1,132 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "SVGLengthList.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "SVGLength.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
SVGLengthList::CopyFrom(const SVGLengthList& rhs)
|
||||
{
|
||||
if (!mLengths.SetCapacity(rhs.Length())) {
|
||||
// Yes, we do want fallible alloc here
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mLengths = rhs.mLengths;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SVGLengthList::GetValueAsString(nsAString& aValue) const
|
||||
{
|
||||
aValue.Truncate();
|
||||
PRUint32 last = mLengths.Length() - 1;
|
||||
for (PRUint32 i = 0; i < mLengths.Length(); ++i) {
|
||||
nsAutoString length;
|
||||
mLengths[i].GetValueAsString(length);
|
||||
// We ignore OOM, since it's not useful for us to return an error.
|
||||
aValue.Append(length);
|
||||
if (i != last) {
|
||||
aValue.Append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline char* SkipWhitespace(char* str)
|
||||
{
|
||||
while (IsSVGWhitespace(*str))
|
||||
++str;
|
||||
return str;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGLengthList::SetValueFromString(const nsAString& aValue)
|
||||
{
|
||||
SVGLengthList temp;
|
||||
|
||||
NS_ConvertUTF16toUTF8 value(aValue);
|
||||
char* start = SkipWhitespace(value.BeginWriting());
|
||||
|
||||
// We can't use strtok with SVG_COMMA_WSP_DELIM because to correctly handle
|
||||
// invalid input in the form of two commas without a value between them, we
|
||||
// would need to know if strtok overwrote a comma or not.
|
||||
|
||||
while (*start != '\0') {
|
||||
int end = strcspn(start, SVG_COMMA_WSP_DELIM);
|
||||
if (end == 0) {
|
||||
// found comma in an invalid location
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
SVGLength length;
|
||||
if (!length.SetValueFromString(NS_ConvertUTF8toUTF16(start, PRUint32(end)))) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
if (!temp.AppendItem(length)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
start = SkipWhitespace(start + end);
|
||||
if (*start == ',') {
|
||||
start = SkipWhitespace(start + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return CopyFrom(temp);
|
||||
}
|
||||
|
||||
PRBool
|
||||
SVGLengthList::operator==(const SVGLengthList& rhs) const
|
||||
{
|
||||
if (Length() != rhs.Length()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
for (PRUint32 i = 0; i < Length(); ++i) {
|
||||
if (!(mLengths[i] == rhs.mLengths[i])) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,352 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SVG Project code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_SVGLENGTHLIST_H__
|
||||
#define MOZILLA_SVGLENGTHLIST_H__
|
||||
|
||||
#include "SVGLength.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsSVGElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* ATTENTION! WARNING! WATCH OUT!!
|
||||
*
|
||||
* Consumers that modify objects of this type absolutely MUST keep the DOM
|
||||
* wrappers for those lists (if any) in sync!! That's why this class is so
|
||||
* locked down.
|
||||
*
|
||||
* The DOM wrapper class for this class is DOMSVGLengthList.
|
||||
*/
|
||||
class SVGLengthList
|
||||
{
|
||||
friend class SVGAnimatedLengthList;
|
||||
friend class DOMSVGLengthList;
|
||||
friend class DOMSVGLength;
|
||||
|
||||
public:
|
||||
|
||||
SVGLengthList(){}
|
||||
~SVGLengthList(){}
|
||||
|
||||
// Only methods that don't make/permit modification to this list are public.
|
||||
// Only our friend classes can access methods that may change us.
|
||||
|
||||
/// This may return an incomplete string on OOM, but that's acceptable.
|
||||
void GetValueAsString(nsAString& aValue) const;
|
||||
|
||||
PRBool IsEmpty() const {
|
||||
return mLengths.IsEmpty();
|
||||
}
|
||||
|
||||
PRUint32 Length() const {
|
||||
return mLengths.Length();
|
||||
}
|
||||
|
||||
const SVGLength& operator[](PRUint32 aIndex) const {
|
||||
return mLengths[aIndex];
|
||||
}
|
||||
|
||||
PRBool operator==(const SVGLengthList& rhs) const;
|
||||
|
||||
PRBool SetCapacity(PRUint32 size) {
|
||||
return mLengths.SetCapacity(size);
|
||||
}
|
||||
|
||||
void Compact() {
|
||||
mLengths.Compact();
|
||||
}
|
||||
|
||||
// Access to methods that can modify objects of this type is deliberately
|
||||
// limited. This is to reduce the chances of someone modifying objects of
|
||||
// this type without taking the necessary steps to keep DOM wrappers in sync.
|
||||
// If you need wider access to these methods, consider adding a method to
|
||||
// SVGAnimatedLengthList and having that class act as an intermediary so it
|
||||
// can take care of keeping DOM wrappers in sync.
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* This may fail on OOM if the internal capacity needs to be increased, in
|
||||
* which case the list will be left unmodified.
|
||||
*/
|
||||
nsresult CopyFrom(const SVGLengthList& rhs);
|
||||
|
||||
SVGLength& operator[](PRUint32 aIndex) {
|
||||
return mLengths[aIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* This may fail (return PR_FALSE) on OOM if the internal capacity is being
|
||||
* increased, in which case the list will be left unmodified.
|
||||
*/
|
||||
PRBool SetLength(PRUint32 aNumberOfItems) {
|
||||
return mLengths.SetLength(aNumberOfItems);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Marking the following private only serves to show which methods are only
|
||||
// used by our friend classes (as opposed to our subclasses) - it doesn't
|
||||
// really provide additional safety.
|
||||
|
||||
nsresult SetValueFromString(const nsAString& aValue);
|
||||
|
||||
void Clear() {
|
||||
mLengths.Clear();
|
||||
}
|
||||
|
||||
PRBool InsertItem(PRUint32 aIndex, const SVGLength &aLength) {
|
||||
if (aIndex >= mLengths.Length()) aIndex = mLengths.Length();
|
||||
return !!mLengths.InsertElementAt(aIndex, aLength);
|
||||
}
|
||||
|
||||
void ReplaceItem(PRUint32 aIndex, const SVGLength &aLength) {
|
||||
NS_ASSERTION(aIndex < mLengths.Length(),
|
||||
"DOM wrapper caller should have raised INDEX_SIZE_ERR");
|
||||
mLengths[aIndex] = aLength;
|
||||
}
|
||||
|
||||
void RemoveItem(PRUint32 aIndex) {
|
||||
NS_ASSERTION(aIndex < mLengths.Length(),
|
||||
"DOM wrapper caller should have raised INDEX_SIZE_ERR");
|
||||
mLengths.RemoveElementAt(aIndex);
|
||||
}
|
||||
|
||||
PRBool AppendItem(SVGLength aLength) {
|
||||
return !!mLengths.AppendElement(aLength);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* Rationale for using nsTArray<SVGLength> and not nsTArray<SVGLength, 1>:
|
||||
*
|
||||
* It might seem like we should use nsAutoTArray<SVGLength, 1> instead of
|
||||
* nsTArray<SVGLength>. That would preallocate space for one SVGLength and
|
||||
* avoid an extra memory allocation call in the common case of the 'x'
|
||||
* and 'y' attributes each containing a single length (and the 'dx' and 'dy'
|
||||
* attributes being empty). However, consider this:
|
||||
*
|
||||
* An empty nsTArray uses sizeof(Header*). An nsAutoTArray<class E,
|
||||
* PRUint32 N> on the other hand uses sizeof(Header*) +
|
||||
* (2 * sizeof(PRUint32)) + (N * sizeof(E)), which for one SVGLength is
|
||||
* sizeof(Header*) + 16 bytes.
|
||||
*
|
||||
* Now consider that for text elements we have four length list attributes
|
||||
* (x, y, dx, dy), each of which can have a baseVal and an animVal list. If
|
||||
* we were to go the nsAutoTArray<SVGLength, 1> route for each of these, we'd
|
||||
* end up using at least 160 bytes for these four attributes alone, even
|
||||
* though we only need storage for two SVGLengths (16 bytes) in the common
|
||||
* case!!
|
||||
*
|
||||
* A compromise might be to template SVGLengthList to allow
|
||||
* SVGAnimatedLengthList to preallocate space for an SVGLength for the
|
||||
* baseVal lists only, and that would cut the space used by the four
|
||||
* attributes to 96 bytes. Taking that even further and templating
|
||||
* SVGAnimatedLengthList too in order to only use nsTArray for 'dx' and 'dy'
|
||||
* would reduce the storage further to 64 bytes. Having different types makes
|
||||
* things more complicated for code that needs to look at the lists though.
|
||||
* In fact it also makes things more complicated when it comes to storing the
|
||||
* lists.
|
||||
*
|
||||
* It may be worth considering using nsAttrValue for length lists instead of
|
||||
* storing them directly on the element.
|
||||
*/
|
||||
nsTArray<SVGLength> mLengths;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This SVGLengthList subclass is for SVGLengthListSMILType which needs to know
|
||||
* which element and attribute a length list belongs to so that it can convert
|
||||
* between unit types if necessary.
|
||||
*/
|
||||
class SVGLengthListAndInfo : public SVGLengthList
|
||||
{
|
||||
public:
|
||||
|
||||
SVGLengthListAndInfo()
|
||||
: mElement(nsnull)
|
||||
, mAxis(0)
|
||||
, mCanZeroPadList(PR_FALSE)
|
||||
{}
|
||||
|
||||
SVGLengthListAndInfo(nsSVGElement *aElement, PRUint8 aAxis, PRBool aCanZeroPadList)
|
||||
: mElement(aElement)
|
||||
, mAxis(aAxis)
|
||||
, mCanZeroPadList(aCanZeroPadList)
|
||||
{}
|
||||
|
||||
void SetInfo(nsSVGElement *aElement, PRUint8 aAxis, PRBool aCanZeroPadList) {
|
||||
mElement = aElement;
|
||||
mAxis = aAxis;
|
||||
mCanZeroPadList = aCanZeroPadList;
|
||||
}
|
||||
|
||||
nsSVGElement* Element() const {
|
||||
return mElement; // .get();
|
||||
}
|
||||
|
||||
PRUint8 Axis() const {
|
||||
NS_ASSERTION(mElement, "Axis() isn't valid");
|
||||
return mAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value returned by this function depends on which attribute this object
|
||||
* is for. If appending a list of zeros to the attribute's list would have no
|
||||
* affect on rendering (e.g. the attributes 'dx' and 'dy' on <text>), then
|
||||
* this method will return PR_TRUE. If appending a list of zeros to the
|
||||
* attribute's list could *change* rendering (e.g. the attributes 'x' and 'y'
|
||||
* on <text>), then this method will return PR_FALSE.
|
||||
*
|
||||
* The reason that this method exists is because the SMIL code needs to know
|
||||
* what to do when it's asked to animate between lists of different length.
|
||||
* If this method returns PR_TRUE, then it can zero pad the short list before
|
||||
* carrying out its operations. However, in the case of the 'x' and 'y'
|
||||
* attributes on <text>, zero would mean "zero in the current coordinate
|
||||
* system", whereas we would want to pad shorter lists with the coordinates
|
||||
* at which glyphs would otherwise lie, which is almost certainly not zero!
|
||||
* Animating from/to zeros in this case would produce terrible results.
|
||||
*
|
||||
* Currently SVGLengthListSMILType simply disallows (drops) animation between
|
||||
* lists of different length if it can't zero pad a list. This is to avoid
|
||||
* having some authors create content that depends on undesirable behaviour
|
||||
* (which would make it difficult for us to fix the behavior in future). At
|
||||
* some point it would be nice to implement a callback to allow this code to
|
||||
* determine padding values for lists that can't be zero padded. See
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=573431
|
||||
*/
|
||||
PRBool CanZeroPadList() const {
|
||||
//NS_ASSERTION(mElement, "CanZeroPadList() isn't valid");
|
||||
return mCanZeroPadList;
|
||||
}
|
||||
|
||||
// For the SMIL code. See comment in SVGLengthListSMILType::Add().
|
||||
void SetCanZeroPadList(PRBool aCanZeroPadList) {
|
||||
mCanZeroPadList = aCanZeroPadList;
|
||||
}
|
||||
|
||||
nsresult CopyFrom(const SVGLengthListAndInfo& rhs) {
|
||||
mElement = rhs.mElement;
|
||||
mAxis = rhs.mAxis;
|
||||
mCanZeroPadList = rhs.mCanZeroPadList;
|
||||
return SVGLengthList::CopyFrom(rhs);
|
||||
}
|
||||
|
||||
// Instances of this special subclass do not have DOM wrappers that we need
|
||||
// to worry about keeping in sync, so it's safe to expose any hidden base
|
||||
// class methods required by the SMIL code, as we do below.
|
||||
|
||||
/**
|
||||
* Exposed so that SVGLengthList baseVals can be copied to
|
||||
* SVGLengthListAndInfo objects. Note that callers should also call
|
||||
* SetInfo() when using this method!
|
||||
*/
|
||||
nsresult CopyFrom(const SVGLengthList& rhs) {
|
||||
return SVGLengthList::CopyFrom(rhs);
|
||||
}
|
||||
const SVGLength& operator[](PRUint32 aIndex) const {
|
||||
return SVGLengthList::operator[](aIndex);
|
||||
}
|
||||
SVGLength& operator[](PRUint32 aIndex) {
|
||||
return SVGLengthList::operator[](aIndex);
|
||||
}
|
||||
PRBool SetLength(PRUint32 aNumberOfItems) {
|
||||
return SVGLengthList::SetLength(aNumberOfItems);
|
||||
}
|
||||
|
||||
private:
|
||||
// We must keep a strong reference to our element because we may belong to a
|
||||
// cached baseVal nsSMILValue. See the comments starting at:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
|
||||
nsRefPtr<nsSVGElement> mElement;
|
||||
PRUint8 mAxis;
|
||||
PRPackedBool mCanZeroPadList;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class wraps SVGLengthList objects to allow frame consumers to process
|
||||
* SVGLengthList objects as if they were simply a list of float values in user
|
||||
* units. When consumers request the value at a given index, this class
|
||||
* dynamically converts the corresponding SVGLength from its actual unit and
|
||||
* returns its value in user units.
|
||||
*
|
||||
* Consumers should check that the user unit values returned are finite. Even
|
||||
* if the consumer can guarantee the list's element has a valid viewport
|
||||
* ancestor to resolve percentage units against, and a valid presContext and
|
||||
* styleContext to resolve absolute and em/ex units against, unit conversions
|
||||
* could still overflow. In that case the value returned will be
|
||||
* numeric_limits<float>::quiet_NaN().
|
||||
*/
|
||||
class NS_STACK_CLASS SVGUserUnitList
|
||||
{
|
||||
public:
|
||||
|
||||
SVGUserUnitList()
|
||||
: mList(nsnull)
|
||||
{}
|
||||
|
||||
void Init(const SVGLengthList *aList, nsSVGElement *aElement, PRUint8 aAxis) {
|
||||
mList = aList;
|
||||
mElement = aElement;
|
||||
mAxis = aAxis;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
mList = nsnull;
|
||||
}
|
||||
|
||||
PRUint32 Length() {
|
||||
return mList ? mList->Length() : 0;
|
||||
}
|
||||
|
||||
/// This may return a non-finite value
|
||||
float operator[](PRUint32 aIndex) {
|
||||
return (*mList)[aIndex].GetValueInUserUnits(mElement, mAxis);
|
||||
}
|
||||
|
||||
private:
|
||||
const SVGLengthList *mList;
|
||||
nsSVGElement *mElement;
|
||||
PRUint8 mAxis;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_SVGLENGTHLIST_H__
|
|
@ -0,0 +1,309 @@
|
|||
/* -*- 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 the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* 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 "SVGLengthListSMILType.h"
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*static*/ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISMILType implementation
|
||||
|
||||
void
|
||||
SVGLengthListSMILType::Init(nsSMILValue &aValue) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
|
||||
|
||||
SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();
|
||||
|
||||
// See the comment documenting Init() in our header file:
|
||||
lengthList->SetCanZeroPadList(PR_TRUE);
|
||||
|
||||
aValue.mU.mPtr = lengthList;
|
||||
aValue.mType = this;
|
||||
}
|
||||
|
||||
void
|
||||
SVGLengthListSMILType::Destroy(nsSMILValue& aValue) const
|
||||
{
|
||||
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
|
||||
delete static_cast<SVGLengthListAndInfo*>(aValue.mU.mPtr);
|
||||
aValue.mU.mPtr = nsnull;
|
||||
aValue.mType = &nsSMILNullType::sSingleton;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGLengthListSMILType::Assign(nsSMILValue& aDest,
|
||||
const nsSMILValue& aSrc) const
|
||||
{
|
||||
NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
|
||||
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
|
||||
|
||||
const SVGLengthListAndInfo* src =
|
||||
static_cast<const SVGLengthListAndInfo*>(aSrc.mU.mPtr);
|
||||
SVGLengthListAndInfo* dest =
|
||||
static_cast<SVGLengthListAndInfo*>(aDest.mU.mPtr);
|
||||
|
||||
return dest->CopyFrom(*src);
|
||||
}
|
||||
|
||||
PRBool
|
||||
SVGLengthListSMILType::IsEqual(const nsSMILValue& aLeft,
|
||||
const nsSMILValue& aRight) const
|
||||
{
|
||||
NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
|
||||
NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
|
||||
|
||||
return *static_cast<const SVGLengthListAndInfo*>(aLeft.mU.mPtr) ==
|
||||
*static_cast<const SVGLengthListAndInfo*>(aRight.mU.mPtr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGLengthListSMILType::Add(nsSMILValue& aDest,
|
||||
const nsSMILValue& aValueToAdd,
|
||||
PRUint32 aCount) const
|
||||
{
|
||||
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
|
||||
NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
|
||||
|
||||
SVGLengthListAndInfo& dest =
|
||||
*static_cast<SVGLengthListAndInfo*>(aDest.mU.mPtr);
|
||||
const SVGLengthListAndInfo& valueToAdd =
|
||||
*static_cast<const SVGLengthListAndInfo*>(aValueToAdd.mU.mPtr);
|
||||
|
||||
// To understand this code, see the comments documenting our Init() method,
|
||||
// and documenting SVGLengthListAndInfo::CanZeroPadList().
|
||||
|
||||
// Note that *this* method actually may safely zero pad a shorter list
|
||||
// regardless of the value returned by CanZeroPadList() for that list,
|
||||
// just so long as the shorter list is being added *to* the longer list
|
||||
// and *not* vice versa! It's okay in the case of adding a shorter list to a
|
||||
// longer list because during the add operation we'll end up adding the
|
||||
// zeros to actual specified values. It's *not* okay in the case of adding a
|
||||
// longer list to a shorter list because then we end up adding to implicit
|
||||
// zeros when we'd actually need to add to whatever the underlying values
|
||||
// should be, not zeros, and those values are not explicit or otherwise
|
||||
// available.
|
||||
|
||||
if (dest.Length() < valueToAdd.Length()) {
|
||||
if (!dest.CanZeroPadList()) {
|
||||
// nsSVGUtils::ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(valueToAdd.CanZeroPadList() || dest.Length() == 0,
|
||||
"Only \"zero\" nsSMILValues from the SMIL engine should "
|
||||
"return PR_TRUE for CanZeroPadList() when the attribute "
|
||||
"being animated can't be zero padded");
|
||||
|
||||
PRUint32 i = dest.Length();
|
||||
if (!dest.SetLength(valueToAdd.Length())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
for (; i < valueToAdd.Length(); ++i) {
|
||||
dest[i].SetValueAndUnit(0.0f, valueToAdd[i].GetUnit());
|
||||
}
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < valueToAdd.Length(); ++i) {
|
||||
float valToAdd;
|
||||
if (dest[i].GetUnit() == valueToAdd[i].GetUnit()) {
|
||||
valToAdd = valueToAdd[i].GetValueInCurrentUnits();
|
||||
} else {
|
||||
// If units differ, we use the unit of the item in 'dest'.
|
||||
// We leave it to the frame code to check that values are finite.
|
||||
valToAdd = valueToAdd[i].GetValueInSpecifiedUnit(dest[i].GetUnit(),
|
||||
dest.Element(),
|
||||
dest.Axis());
|
||||
}
|
||||
dest[i].SetValueAndUnit(dest[i].GetValueInCurrentUnits() + valToAdd,
|
||||
dest[i].GetUnit());
|
||||
}
|
||||
|
||||
// propagate flag:
|
||||
dest.SetCanZeroPadList(dest.CanZeroPadList() &&
|
||||
valueToAdd.CanZeroPadList());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGLengthListSMILType::ComputeDistance(const nsSMILValue& aFrom,
|
||||
const nsSMILValue& aTo,
|
||||
double& aDistance) const
|
||||
{
|
||||
NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
|
||||
NS_PRECONDITION(aTo.mType == this, "Incompatible SMIL type");
|
||||
|
||||
const SVGLengthListAndInfo& from =
|
||||
*static_cast<const SVGLengthListAndInfo*>(aFrom.mU.mPtr);
|
||||
const SVGLengthListAndInfo& to =
|
||||
*static_cast<const SVGLengthListAndInfo*>(aTo.mU.mPtr);
|
||||
|
||||
// To understand this code, see the comments documenting our Init() method,
|
||||
// and documenting SVGLengthListAndInfo::CanZeroPadList().
|
||||
|
||||
NS_ASSERTION(from.CanZeroPadList() == to.CanZeroPadList() ||
|
||||
from.CanZeroPadList() && from.Length() == 0 ||
|
||||
to.CanZeroPadList() && to.Length() == 0,
|
||||
"Only \"zero\" nsSMILValues from the SMIL engine should "
|
||||
"return PR_TRUE for CanZeroPadList() when the attribute "
|
||||
"being animated can't be zero padded");
|
||||
|
||||
if ((from.Length() < to.Length() && !from.CanZeroPadList()) ||
|
||||
(to.Length() < from.Length() && !to.CanZeroPadList())) {
|
||||
// nsSVGUtils::ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We return the root of the sum of the squares of the deltas between the
|
||||
// user unit values of the lengths at each correspanding index. In the
|
||||
// general case, paced animation is probably not useful, but this strategy at
|
||||
// least does the right thing for paced animation in the face of simple
|
||||
// 'values' lists such as:
|
||||
//
|
||||
// values="100 200 300; 101 201 301; 110 210 310"
|
||||
//
|
||||
// I.e. half way through the simple duration we'll get "105 205 305".
|
||||
|
||||
double total = 0.0;
|
||||
|
||||
PRUint32 i = 0;
|
||||
for (; i < from.Length() && i < to.Length(); ++i) {
|
||||
double f = from[i].GetValueInUserUnits(from.Element(), from.Axis());
|
||||
double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
|
||||
double delta = t - f;
|
||||
total += delta * delta;
|
||||
}
|
||||
|
||||
// In the case that from.Length() != to.Length(), one of the following loops
|
||||
// will run. (OK since CanZeroPadList()==true for the other list.)
|
||||
|
||||
for (; i < from.Length(); ++i) {
|
||||
double f = from[i].GetValueInUserUnits(from.Element(), from.Axis());
|
||||
total += f * f;
|
||||
}
|
||||
for (; i < to.Length(); ++i) {
|
||||
double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
|
||||
total += t * t;
|
||||
}
|
||||
|
||||
float distance = sqrt(total);
|
||||
if (!NS_FloatIsFinite(distance)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aDistance = distance;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGLengthListSMILType::Interpolate(const nsSMILValue& aStartVal,
|
||||
const nsSMILValue& aEndVal,
|
||||
double aUnitDistance,
|
||||
nsSMILValue& aResult) const
|
||||
{
|
||||
NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
|
||||
"Trying to interpolate different types");
|
||||
NS_PRECONDITION(aStartVal.mType == this,
|
||||
"Unexpected types for interpolation");
|
||||
NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
|
||||
|
||||
const SVGLengthListAndInfo& start =
|
||||
*static_cast<const SVGLengthListAndInfo*>(aStartVal.mU.mPtr);
|
||||
const SVGLengthListAndInfo& end =
|
||||
*static_cast<const SVGLengthListAndInfo*>(aEndVal.mU.mPtr);
|
||||
SVGLengthListAndInfo& result =
|
||||
*static_cast<SVGLengthListAndInfo*>(aResult.mU.mPtr);
|
||||
|
||||
// To understand this code, see the comments documenting our Init() method,
|
||||
// and documenting SVGLengthListAndInfo::CanZeroPadList().
|
||||
|
||||
NS_ASSERTION(start.CanZeroPadList() == end.CanZeroPadList() ||
|
||||
start.CanZeroPadList() && start.Length() == 0 ||
|
||||
end.CanZeroPadList() && end.Length() == 0,
|
||||
"Only \"zero\" nsSMILValues from the SMIL engine should "
|
||||
"return PR_TRUE for CanZeroPadList() when the attribute "
|
||||
"being animated can't be zero padded");
|
||||
|
||||
if ((start.Length() < end.Length() && !start.CanZeroPadList()) ||
|
||||
(end.Length() < start.Length() && !end.CanZeroPadList())) {
|
||||
// nsSVGUtils::ReportToConsole
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!result.SetLength(NS_MAX(start.Length(), end.Length()))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PRUint32 i = 0;
|
||||
for (; i < start.Length() && i < end.Length(); ++i) {
|
||||
float s;
|
||||
if (start[i].GetUnit() == end[i].GetUnit()) {
|
||||
s = start[i].GetValueInCurrentUnits();
|
||||
} else {
|
||||
// If units differ, we use the unit of the item in 'end'.
|
||||
// We leave it to the frame code to check that values are finite.
|
||||
s = start[i].GetValueInSpecifiedUnit(end[i].GetUnit(), end.Element(), end.Axis());
|
||||
}
|
||||
float e = end[i].GetValueInCurrentUnits();
|
||||
result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, end[i].GetUnit());
|
||||
}
|
||||
|
||||
// In the case that start.Length() != end.Length(), one of the following
|
||||
// loops will run. (Okay, since CanZeroPadList()==true for the other list.)
|
||||
|
||||
for (; i < start.Length(); ++i) {
|
||||
result[i].SetValueAndUnit(start[i].GetValueInCurrentUnits() -
|
||||
start[i].GetValueInCurrentUnits() * aUnitDistance,
|
||||
start[i].GetUnit());
|
||||
}
|
||||
for (; i < end.Length(); ++i) {
|
||||
result[i].SetValueAndUnit(end[i].GetValueInCurrentUnits() * aUnitDistance,
|
||||
end[i].GetUnit());
|
||||
}
|
||||
|
||||
// propagate flag:
|
||||
result.SetCanZeroPadList(start.CanZeroPadList() &&
|
||||
end.CanZeroPadList());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,132 @@
|
|||
/* -*- 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 the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* 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_SVGLENGTHLISTSMILTYPE_H_
|
||||
#define MOZILLA_SVGLENGTHLISTSMILTYPE_H_
|
||||
|
||||
#include "nsISMILType.h"
|
||||
|
||||
class nsSMILValue;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SVGLengthListSMILType
|
||||
//
|
||||
// Operations for animating an SVGLengthList.
|
||||
//
|
||||
class SVGLengthListSMILType : public nsISMILType
|
||||
{
|
||||
public:
|
||||
// Singleton for nsSMILValue objects to hold onto.
|
||||
static SVGLengthListSMILType sSingleton;
|
||||
|
||||
protected:
|
||||
// nsISMILType Methods
|
||||
// -------------------
|
||||
|
||||
/**
|
||||
* When this method initializes the SVGLengthListAndInfo for its nsSMILValue
|
||||
* argument, it has to blindly set its mCanZeroPadList to PR_TRUE despite
|
||||
* the fact that some attributes can't be zero-padded. (See the explaination
|
||||
* that follows.) SVGAnimatedLengthList::SMILAnimatedLengthList's
|
||||
* GetBaseValue() and ValueFromString() methods then override this for the
|
||||
* nsSMILValue objects that they create to set this flag to the appropriate
|
||||
* value for the attribute in question.
|
||||
*
|
||||
* The reason that we default to setting the mCanZeroPadList to true is
|
||||
* because the SMIL engine creates "zero" valued nsSMILValue objects for
|
||||
* intermediary calculations, and may pass such an nsSMILValue (along with an
|
||||
* nsSMILValue from an animation element - that is an nsSMILValue created by
|
||||
* SVGAnimatedLengthList::SMILAnimatedLengthList's GetBaseValue() or
|
||||
* ValueFromString() methods) into the Add(), ComputeDistance() or
|
||||
* Interpolate() methods below. Even in the case of animation of list
|
||||
* attributes that may *not* be padded with zeros (such as 'x' and 'y' on the
|
||||
* <text> element), we need to allow zero-padding of these "zero" valued
|
||||
* nsSMILValue's lists. One reason for this is illustrated by the following
|
||||
* example:
|
||||
*
|
||||
* <text x="2 4">foo
|
||||
* <animate by="2 2" .../>
|
||||
* </text>
|
||||
*
|
||||
* In this example there are two SMIL animation layers to be sandwiched: the
|
||||
* base layer, and the layer created for the <animate> element. The SMIL
|
||||
* engine calculates the result of each layer *independently*, before
|
||||
* compositing the results together. Thus for the <animate> sandwich layer
|
||||
* the SMIL engine interpolates between a "zero" nsSMILValue that it creates
|
||||
* (since there is no explicit "from") and the "2 2", before the result of
|
||||
* that interpolation is added to the "2 4" from the base layer. Clearly for
|
||||
* the interpolation between the "zero" nsSMILValue and "2 2" to work, the
|
||||
* "zero" nsSMILValue's SVGLengthListAndInfo must be zero paddable - hence
|
||||
* why this method always sets mCanZeroPadList to PR_TRUE.
|
||||
*
|
||||
* (Since the Add(), ComputeDistance() and Interpolate() methods may be
|
||||
* passed two input nsSMILValue objects for which CanZeroPadList() returns
|
||||
* opposite values, these methods must be careful what they set the flag to
|
||||
* on the nsSMILValue that they output. If *either* of the input nsSMILValues
|
||||
* has an SVGLengthListAndInfo for which CanZeroPadList() returns PR_FALSE,
|
||||
* then they must set the flag to PR_FALSE on the output nsSMILValue too. If
|
||||
* the methods failed to do that, then when the result nsSMILValue objects
|
||||
* from each sandwich layer are composited together, we could end up allowing
|
||||
* animation between lists of different length when we should not!)
|
||||
*/
|
||||
virtual void Init(nsSMILValue& aValue) const;
|
||||
|
||||
virtual void Destroy(nsSMILValue& aValue) const;
|
||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||
virtual PRBool IsEqual(const nsSMILValue& aLeft,
|
||||
const nsSMILValue& aRight) const;
|
||||
virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
|
||||
PRUint32 aCount) const;
|
||||
virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
|
||||
const nsSMILValue& aTo,
|
||||
double& aDistance) const;
|
||||
virtual nsresult Interpolate(const nsSMILValue& aStartVal,
|
||||
const nsSMILValue& aEndVal,
|
||||
double aUnitDistance,
|
||||
nsSMILValue& aResult) const;
|
||||
|
||||
private:
|
||||
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||
// and prevent others from deleting my singleton.
|
||||
SVGLengthListSMILType() {}
|
||||
~SVGLengthListSMILType() {}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_SVGLENGTHLISTSMILTYPE_H_
|
|
@ -1,206 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* 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 "nsSVGAnimatedLengthList.h"
|
||||
#include "nsSVGLengthList.h"
|
||||
#include "nsSVGValue.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGAnimatedTransformList
|
||||
|
||||
class nsSVGAnimatedLengthList : public nsIDOMSVGAnimatedLengthList,
|
||||
public nsSVGValue,
|
||||
public nsISVGValueObserver
|
||||
{
|
||||
protected:
|
||||
friend nsresult
|
||||
NS_NewSVGAnimatedLengthList(nsIDOMSVGAnimatedLengthList** result,
|
||||
nsIDOMSVGLengthList* baseVal);
|
||||
|
||||
nsSVGAnimatedLengthList();
|
||||
~nsSVGAnimatedLengthList();
|
||||
void Init(nsIDOMSVGLengthList* baseVal);
|
||||
|
||||
public:
|
||||
// nsISupports interface:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIDOMSVGAnimatedLengthList interface:
|
||||
NS_DECL_NSIDOMSVGANIMATEDLENGTHLIST
|
||||
|
||||
// remainder of nsISVGValue interface:
|
||||
NS_IMETHOD SetValueString(const nsAString& aValue);
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
// nsISVGValueObserver
|
||||
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
|
||||
modificationType aModType);
|
||||
NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
|
||||
modificationType aModType);
|
||||
|
||||
// nsISupportsWeakReference
|
||||
// implementation inherited from nsSupportsWeakReference
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMSVGLengthList> mBaseVal;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
nsSVGAnimatedLengthList::nsSVGAnimatedLengthList()
|
||||
{
|
||||
}
|
||||
|
||||
nsSVGAnimatedLengthList::~nsSVGAnimatedLengthList()
|
||||
{
|
||||
if (!mBaseVal) return;
|
||||
nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
|
||||
if (!val) return;
|
||||
val->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAnimatedLengthList::Init(nsIDOMSVGLengthList* baseVal)
|
||||
{
|
||||
mBaseVal = baseVal;
|
||||
if (!mBaseVal) return;
|
||||
nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
|
||||
if (!val) return;
|
||||
val->AddObserver(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods:
|
||||
|
||||
NS_IMPL_ADDREF(nsSVGAnimatedLengthList)
|
||||
NS_IMPL_RELEASE(nsSVGAnimatedLengthList)
|
||||
|
||||
DOMCI_DATA(SVGAnimatedLengthList, nsSVGAnimatedLengthList)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsSVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGValue methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::SetValueString(const nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsISVGValue> value = do_QueryInterface(mBaseVal);
|
||||
return value->SetValueString(aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::GetValueString(nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsISVGValue> value = do_QueryInterface(mBaseVal);
|
||||
return value->GetValueString(aValue);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGAnimatedLengthList methods:
|
||||
|
||||
/* readonly attribute nsIDOMSVGLengthList baseVal; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::GetBaseVal(nsIDOMSVGLengthList * *aBaseVal)
|
||||
{
|
||||
*aBaseVal = mBaseVal;
|
||||
NS_ADDREF(*aBaseVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGLengthList animVal; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::GetAnimVal(nsIDOMSVGLengthList * *aAnimVal)
|
||||
{
|
||||
*aAnimVal = mBaseVal;
|
||||
NS_ADDREF(*aAnimVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGValueObserver methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::WillModifySVGObservable(nsISVGValue* observable,
|
||||
modificationType aModType)
|
||||
{
|
||||
WillModify(aModType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGAnimatedLengthList::DidModifySVGObservable (nsISVGValue* observable,
|
||||
modificationType aModType)
|
||||
{
|
||||
DidModify(aModType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Exported creation functions:
|
||||
|
||||
nsresult
|
||||
NS_NewSVGAnimatedLengthList(nsIDOMSVGAnimatedLengthList** result,
|
||||
nsIDOMSVGLengthList* baseVal)
|
||||
{
|
||||
*result = nsnull;
|
||||
|
||||
nsSVGAnimatedLengthList* animatedLengthList = new nsSVGAnimatedLengthList();
|
||||
if(!animatedLengthList) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(animatedLengthList);
|
||||
|
||||
animatedLengthList->Init(baseVal);
|
||||
|
||||
*result = (nsIDOMSVGAnimatedLengthList*) animatedLengthList;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* 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_SVGANIMATEDLENGTHLIST_H__
|
||||
#define __NS_SVGANIMATEDLENGTHLIST_H__
|
||||
|
||||
#include "nsIDOMSVGAnimatedLengthList.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
|
||||
nsresult
|
||||
NS_NewSVGAnimatedLengthList(nsIDOMSVGAnimatedLengthList** result,
|
||||
nsIDOMSVGLengthList* baseVal);
|
||||
|
||||
#endif //__NS_SVGANIMATEDLENGTHLIST_H__
|
|
@ -74,15 +74,12 @@
|
|||
#include "nsSVGEnum.h"
|
||||
#include "nsSVGViewBox.h"
|
||||
#include "nsSVGString.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "nsIDOMSVGUnitTypes.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
#include "nsIDOMSVGAnimatedLengthList.h"
|
||||
#include "nsIDOMSVGNumberList.h"
|
||||
#include "nsIDOMSVGAnimatedNumberList.h"
|
||||
#include "nsIDOMSVGPointList.h"
|
||||
#include "nsIDOMSVGAnimatedPoints.h"
|
||||
#include "nsIDOMSVGPresAspectRatio.h"
|
||||
#include "nsIDOMSVGAnimPresAspRatio.h"
|
||||
#include "nsIDOMSVGTransformList.h"
|
||||
#include "nsIDOMSVGAnimTransformList.h"
|
||||
#include "nsIDOMSVGAnimatedRect.h"
|
||||
|
@ -174,6 +171,12 @@ nsSVGElement::Init()
|
|||
preserveAspectRatio->Init();
|
||||
}
|
||||
|
||||
LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
|
||||
|
||||
for (i = 0; i < lengthListInfo.mLengthListCount; i++) {
|
||||
lengthListInfo.Reset(i);
|
||||
}
|
||||
|
||||
StringAttributesInfo stringInfo = GetStringInfo();
|
||||
|
||||
for (i = 0; i < stringInfo.mStringCount; i++) {
|
||||
|
@ -352,6 +355,22 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
|
|||
}
|
||||
}
|
||||
|
||||
if (!foundMatch) {
|
||||
// Check for SVGAnimatedLengthList attribute
|
||||
LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
|
||||
for (i = 0; i < lengthListInfo.mLengthListCount; i++) {
|
||||
if (aAttribute == *lengthListInfo.mLengthListInfo[i].mName) {
|
||||
rv = lengthListInfo.mLengthLists[i].SetBaseValueString(aValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
// ReportToConsole
|
||||
lengthListInfo.Reset(i);
|
||||
}
|
||||
foundMatch = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatch) {
|
||||
// Check for nsSVGNumber2 attribute
|
||||
NumberAttributesInfo numberInfo = GetNumberInfo();
|
||||
|
@ -533,6 +552,20 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
}
|
||||
}
|
||||
|
||||
if (!foundMatch) {
|
||||
// Check if this is a length list attribute going away
|
||||
LengthListAttributesInfo lengthListInfo = GetLengthListInfo();
|
||||
|
||||
for (PRUint32 i = 0; i < lengthListInfo.mLengthListCount; i++) {
|
||||
if (aName == *lengthListInfo.mLengthListInfo[i].mName) {
|
||||
lengthListInfo.Reset(i);
|
||||
DidChangeLengthList(i, PR_FALSE);
|
||||
foundMatch = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatch) {
|
||||
// Check if this is a number attribute going away
|
||||
NumberAttributesInfo numInfo = GetNumberInfo();
|
||||
|
@ -669,12 +702,6 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
void
|
||||
nsSVGElement::ResetOldStyleBaseType(nsISVGValue *svg_value)
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> ll = do_QueryInterface(svg_value);
|
||||
if (ll) {
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthlist;
|
||||
ll->GetBaseVal(getter_AddRefs(lengthlist));
|
||||
lengthlist->Clear();
|
||||
}
|
||||
nsCOMPtr<nsIDOMSVGAnimatedNumberList> nl = do_QueryInterface(svg_value);
|
||||
if (nl) {
|
||||
nsCOMPtr<nsIDOMSVGNumberList> numberlist;
|
||||
|
@ -1430,6 +1457,85 @@ nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
nsSVGElement::LengthListAttributesInfo
|
||||
nsSVGElement::GetLengthListInfo()
|
||||
{
|
||||
return LengthListAttributesInfo(nsnull, nsnull, 0);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::LengthListAttributesInfo::Reset(PRUint8 aAttrEnum)
|
||||
{
|
||||
mLengthLists[aAttrEnum].ClearBaseValue(aAttrEnum);
|
||||
// caller notifies
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::DidChangeLengthList(PRUint8 aAttrEnum, PRBool aDoSetAttr)
|
||||
{
|
||||
if (!aDoSetAttr)
|
||||
return;
|
||||
|
||||
LengthListAttributesInfo info = GetLengthListInfo();
|
||||
|
||||
NS_ASSERTION(info.mLengthListCount > 0,
|
||||
"DidChangeLengthList on element with no length list attribs");
|
||||
NS_ASSERTION(aAttrEnum < info.mLengthListCount, "aAttrEnum out of range");
|
||||
|
||||
nsAutoString newStr;
|
||||
info.mLengthLists[aAttrEnum].GetBaseValue().GetValueAsString(newStr);
|
||||
|
||||
SetAttr(kNameSpaceID_None, *info.mLengthListInfo[aAttrEnum].mName,
|
||||
newStr, PR_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::DidAnimateLengthList(PRUint8 aAttrEnum)
|
||||
{
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
|
||||
if (frame) {
|
||||
LengthListAttributesInfo info = GetLengthListInfo();
|
||||
frame->AttributeChanged(kNameSpaceID_None,
|
||||
*info.mLengthListInfo[aAttrEnum].mName,
|
||||
nsIDOMMutationEvent::MODIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...)
|
||||
{
|
||||
LengthListAttributesInfo info = GetLengthListInfo();
|
||||
|
||||
NS_ASSERTION(info.mLengthListCount > 0,
|
||||
"GetAnimatedLengthListValues on element with no length list attribs");
|
||||
|
||||
SVGUserUnitList *list = aFirst;
|
||||
PRUint32 i = 0;
|
||||
|
||||
va_list args;
|
||||
va_start(args, aFirst);
|
||||
|
||||
while (list && i < info.mLengthListCount) {
|
||||
list->Init(&(info.mLengthLists[i].GetAnimValue()), this, info.mLengthListInfo[i].mAxis);
|
||||
++i;
|
||||
list = va_arg(args, SVGUserUnitList*);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
SVGAnimatedLengthList*
|
||||
nsSVGElement::GetAnimatedLengthList(PRUint8 aAttrEnum)
|
||||
{
|
||||
LengthListAttributesInfo info = GetLengthListInfo();
|
||||
if (aAttrEnum < info.mLengthListCount) {
|
||||
return &(info.mLengthLists[aAttrEnum]);
|
||||
}
|
||||
NS_NOTREACHED("Bad attrEnum");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsSVGElement::NumberAttributesInfo
|
||||
nsSVGElement::GetNumberInfo()
|
||||
{
|
||||
|
@ -2059,6 +2165,20 @@ nsSVGElement::GetAnimatedAttr(nsIAtom* aName)
|
|||
return preserveAspectRatio ? preserveAspectRatio->ToSMILAttr(this) : nsnull;
|
||||
}
|
||||
|
||||
// LengthLists:
|
||||
{
|
||||
LengthListAttributesInfo info = GetLengthListInfo();
|
||||
for (PRUint32 i = 0; i < info.mLengthListCount; i++) {
|
||||
if (aName == *info.mLengthListInfo[i].mName) {
|
||||
NS_ABORT_IF_FALSE(i <= UCHAR_MAX, "Too many attributes");
|
||||
return info.mLengthLists[i].ToSMILAttr(this,
|
||||
PRUint8(i),
|
||||
info.mLengthListInfo[i].mAxis,
|
||||
info.mLengthListInfo[i].mCouldZeroPadList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mapped attributes:
|
||||
if (IsAttributeMapped(aName)) {
|
||||
nsCSSProperty prop = nsCSSProps::LookupProperty(nsAtomString(aName));
|
||||
|
|
|
@ -71,6 +71,12 @@ class nsSVGViewBox;
|
|||
class nsSVGPreserveAspectRatio;
|
||||
class nsSVGString;
|
||||
struct gfxMatrix;
|
||||
namespace mozilla {
|
||||
class SVGAnimatedLengthList;
|
||||
class SVGUserUnitList;
|
||||
}
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef nsStyledElement nsSVGElementBase;
|
||||
|
||||
|
@ -159,6 +165,7 @@ public:
|
|||
virtual void DidChangeEnum(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
||||
virtual void DidChangeViewBox(PRBool aDoSetAttr);
|
||||
virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
|
||||
virtual void DidChangeLengthList(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
||||
virtual void DidChangeString(PRUint8 aAttrEnum) {}
|
||||
|
||||
virtual void DidAnimateLength(PRUint8 aAttrEnum);
|
||||
|
@ -169,11 +176,14 @@ public:
|
|||
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
|
||||
virtual void DidAnimateViewBox();
|
||||
virtual void DidAnimatePreserveAspectRatio();
|
||||
virtual void DidAnimateLengthList(PRUint8 aAttrEnum);
|
||||
virtual void DidAnimateTransform();
|
||||
|
||||
void GetAnimatedLengthValues(float *aFirst, ...);
|
||||
void GetAnimatedNumberValues(float *aFirst, ...);
|
||||
void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
|
||||
void GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...);
|
||||
SVGAnimatedLengthList* GetAnimatedLengthList(PRUint8 aAttrEnum);
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
virtual nsISMILAttr* GetAnimatedAttr(nsIAtom* aName);
|
||||
|
@ -330,6 +340,36 @@ protected:
|
|||
void Reset(PRUint8 aAttrEnum);
|
||||
};
|
||||
|
||||
struct LengthListInfo {
|
||||
nsIAtom** mName;
|
||||
PRUint8 mAxis;
|
||||
/**
|
||||
* Flag to indicate whether appending zeros to the end of the list would
|
||||
* change the rendering of the SVG for the attribute in question. For x and
|
||||
* y on the <text> element this is true, but for dx and dy on <text> this
|
||||
* is false. This flag is fed down to SVGLengthListSMILType so it can
|
||||
* determine if it can sensibly animate from-to lists of different lengths,
|
||||
* which is desirable in the case of dx and dy.
|
||||
*/
|
||||
PRPackedBool mCouldZeroPadList;
|
||||
};
|
||||
|
||||
struct LengthListAttributesInfo {
|
||||
SVGAnimatedLengthList* mLengthLists;
|
||||
LengthListInfo* mLengthListInfo;
|
||||
PRUint32 mLengthListCount;
|
||||
|
||||
LengthListAttributesInfo(SVGAnimatedLengthList *aLengthLists,
|
||||
LengthListInfo *aLengthListInfo,
|
||||
PRUint32 aLengthListCount)
|
||||
: mLengthLists(aLengthLists)
|
||||
, mLengthListInfo(aLengthListInfo)
|
||||
, mLengthListCount(aLengthListCount)
|
||||
{}
|
||||
|
||||
void Reset(PRUint8 aAttrEnum);
|
||||
};
|
||||
|
||||
struct StringInfo {
|
||||
nsIAtom** mName;
|
||||
PRInt32 mNamespaceID;
|
||||
|
@ -359,6 +399,7 @@ protected:
|
|||
// so we don't need to wrap the class
|
||||
virtual nsSVGViewBox *GetViewBox();
|
||||
virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
|
||||
virtual LengthListAttributesInfo GetLengthListInfo();
|
||||
virtual StringAttributesInfo GetStringInfo();
|
||||
|
||||
static nsSVGEnumMapping sSVGUnitTypesMap[];
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include "nsIFrame.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "nsSVGLengthList.h"
|
||||
#include "nsIDOMSVGURIReference.h"
|
||||
#include "nsImageLoadingContent.h"
|
||||
#include "imgIContainer.h"
|
||||
|
|
|
@ -1,522 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
* Jonathan Watt <jonathan.watt@strath.ac.uk>
|
||||
*
|
||||
* 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 "nsSVGLength.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSVGValue.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsSVGSVGElement.h"
|
||||
#include "nsIDOMSVGNumber.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGLength class
|
||||
|
||||
class nsSVGLength : public nsISVGLength,
|
||||
public nsSVGValue
|
||||
{
|
||||
protected:
|
||||
friend nsresult NS_NewSVGLength(nsISVGLength** result,
|
||||
float value,
|
||||
PRUint16 unit);
|
||||
|
||||
friend nsresult NS_NewSVGLength(nsISVGLength** result,
|
||||
const nsAString &value);
|
||||
|
||||
nsSVGLength(float value, PRUint16 unit);
|
||||
nsSVGLength();
|
||||
|
||||
public:
|
||||
// nsISupports interface:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIDOMSVGLength interface:
|
||||
NS_DECL_NSIDOMSVGLENGTH
|
||||
|
||||
// nsISVGLength interface:
|
||||
NS_IMETHOD SetContext(nsIWeakReference *aContext, PRUint8 aCtxType);
|
||||
|
||||
// nsISVGValue interface:
|
||||
NS_IMETHOD SetValueString(const nsAString& aValue);
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
// nsISupportsWeakReference
|
||||
// implementation inherited from nsSupportsWeakReference
|
||||
|
||||
protected:
|
||||
// implementation helpers:
|
||||
float mmPerPixel();
|
||||
float AxisLength();
|
||||
float EmLength();
|
||||
float ExLength();
|
||||
PRBool IsValidUnitType(PRUint16 unit);
|
||||
|
||||
nsWeakPtr mElement; // owning element - weakptr to avoid reference loop
|
||||
float mValueInSpecifiedUnits;
|
||||
PRUint16 mSpecifiedUnitType;
|
||||
PRUint8 mCtxType;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLength(nsISVGLength** result,
|
||||
float value,
|
||||
PRUint16 unit)
|
||||
{
|
||||
*result = new nsSVGLength(value, unit);
|
||||
if (!*result)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLength(nsISVGLength** result,
|
||||
const nsAString &value)
|
||||
{
|
||||
*result = nsnull;
|
||||
nsSVGLength *pl = new nsSVGLength();
|
||||
if (!pl)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(pl);
|
||||
nsresult rv = pl->SetValueAsString(value);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(pl);
|
||||
return rv;
|
||||
}
|
||||
*result = pl;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsSVGLength::nsSVGLength(float value,
|
||||
PRUint16 unit)
|
||||
: mValueInSpecifiedUnits(value),
|
||||
mSpecifiedUnitType(unit),
|
||||
mCtxType(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsSVGLength::nsSVGLength()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods:
|
||||
|
||||
NS_IMPL_ADDREF(nsSVGLength)
|
||||
NS_IMPL_RELEASE(nsSVGLength)
|
||||
|
||||
DOMCI_DATA(SVGLength, nsSVGLength)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsSVGLength)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGLength)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGValue methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::SetValueString(const nsAString& aValue)
|
||||
{
|
||||
return SetValueAsString(aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::GetValueString(nsAString& aValue)
|
||||
{
|
||||
return GetValueAsString(aValue);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGLength methods:
|
||||
|
||||
/* readonly attribute unsigned short unitType; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::GetUnitType(PRUint16 *aUnitType)
|
||||
{
|
||||
*aUnitType = mSpecifiedUnitType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute float value; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::GetValue(float *aValue)
|
||||
{
|
||||
switch (mSpecifiedUnitType) {
|
||||
case SVG_LENGTHTYPE_NUMBER:
|
||||
case SVG_LENGTHTYPE_PX:
|
||||
*aValue = mValueInSpecifiedUnits;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_MM:
|
||||
*aValue = mValueInSpecifiedUnits / mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_CM:
|
||||
*aValue = mValueInSpecifiedUnits * 10.0f / mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_IN:
|
||||
*aValue = mValueInSpecifiedUnits * 25.4f / mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PT:
|
||||
*aValue = mValueInSpecifiedUnits * 25.4f / POINTS_PER_INCH_FLOAT /
|
||||
mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PC:
|
||||
*aValue = mValueInSpecifiedUnits * 25.4f * 12.0f / POINTS_PER_INCH_FLOAT /
|
||||
mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PERCENTAGE:
|
||||
*aValue = mValueInSpecifiedUnits * AxisLength() / 100.0f;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EMS:
|
||||
*aValue = mValueInSpecifiedUnits * EmLength();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EXS:
|
||||
*aValue = mValueInSpecifiedUnits * ExLength();
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit type");
|
||||
*aValue = 0;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::SetValue(float aValue)
|
||||
{
|
||||
NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
WillModify();
|
||||
|
||||
switch (mSpecifiedUnitType) {
|
||||
case SVG_LENGTHTYPE_NUMBER:
|
||||
case SVG_LENGTHTYPE_PX:
|
||||
mValueInSpecifiedUnits = aValue;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_MM:
|
||||
mValueInSpecifiedUnits = aValue * mmPerPixel();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_CM:
|
||||
mValueInSpecifiedUnits = aValue * mmPerPixel() / 10.0f;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_IN:
|
||||
mValueInSpecifiedUnits = aValue * mmPerPixel() / 25.4f;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PT:
|
||||
mValueInSpecifiedUnits = aValue * mmPerPixel() * POINTS_PER_INCH_FLOAT /
|
||||
25.4f;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PC:
|
||||
mValueInSpecifiedUnits = aValue * mmPerPixel() * POINTS_PER_INCH_FLOAT /
|
||||
24.4f / 12.0f;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PERCENTAGE:
|
||||
mValueInSpecifiedUnits = aValue * 100.0f / AxisLength();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EMS:
|
||||
mValueInSpecifiedUnits = aValue / EmLength();
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EXS:
|
||||
mValueInSpecifiedUnits = aValue / ExLength();
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit type");
|
||||
mValueInSpecifiedUnits = 0;
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
DidModify();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* attribute float valueInSpecifiedUnits; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::GetValueInSpecifiedUnits(float *aValueInSpecifiedUnits)
|
||||
{
|
||||
*aValueInSpecifiedUnits = mValueInSpecifiedUnits;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::SetValueInSpecifiedUnits(float aValueInSpecifiedUnits)
|
||||
{
|
||||
NS_ENSURE_FINITE(aValueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
|
||||
WillModify();
|
||||
mValueInSpecifiedUnits = aValueInSpecifiedUnits;
|
||||
DidModify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute DOMString valueAsString; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::GetValueAsString(nsAString & aValueAsString)
|
||||
{
|
||||
PRUnichar buf[24];
|
||||
nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
|
||||
NS_LITERAL_STRING("%g").get(),
|
||||
(double)mValueInSpecifiedUnits);
|
||||
aValueAsString.Assign(buf);
|
||||
|
||||
nsIAtom* UnitAtom = nsnull;
|
||||
|
||||
switch (mSpecifiedUnitType) {
|
||||
case SVG_LENGTHTYPE_NUMBER:
|
||||
return NS_OK;
|
||||
case SVG_LENGTHTYPE_PX:
|
||||
UnitAtom = nsGkAtoms::px;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_MM:
|
||||
UnitAtom = nsGkAtoms::mm;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_CM:
|
||||
UnitAtom = nsGkAtoms::cm;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_IN:
|
||||
UnitAtom = nsGkAtoms::in;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PT:
|
||||
UnitAtom = nsGkAtoms::pt;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PC:
|
||||
UnitAtom = nsGkAtoms::pc;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EMS:
|
||||
UnitAtom = nsGkAtoms::em;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_EXS:
|
||||
UnitAtom = nsGkAtoms::ex;
|
||||
break;
|
||||
case SVG_LENGTHTYPE_PERCENTAGE:
|
||||
UnitAtom = nsGkAtoms::percentage;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
aValueAsString.Append(nsDependentAtomString(UnitAtom));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::SetValueAsString(const nsAString & aValueAsString)
|
||||
{
|
||||
nsresult rv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
char *str = ToNewCString(aValueAsString);
|
||||
|
||||
char* number = str;
|
||||
while (*number && IsSVGWhitespace(*number))
|
||||
++number;
|
||||
|
||||
if (*number) {
|
||||
char *rest;
|
||||
float value = float(PR_strtod(number, &rest));
|
||||
if (rest != number) {
|
||||
const char* unitStr = nsCRT::strtok(rest, SVG_WSP_DELIM, &rest);
|
||||
PRUint16 unitType = SVG_LENGTHTYPE_UNKNOWN;
|
||||
if (!unitStr || *unitStr=='\0') {
|
||||
unitType = SVG_LENGTHTYPE_NUMBER;
|
||||
} else {
|
||||
nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
|
||||
if (unitAtom == nsGkAtoms::px)
|
||||
unitType = SVG_LENGTHTYPE_PX;
|
||||
else if (unitAtom == nsGkAtoms::mm)
|
||||
unitType = SVG_LENGTHTYPE_MM;
|
||||
else if (unitAtom == nsGkAtoms::cm)
|
||||
unitType = SVG_LENGTHTYPE_CM;
|
||||
else if (unitAtom == nsGkAtoms::in)
|
||||
unitType = SVG_LENGTHTYPE_IN;
|
||||
else if (unitAtom == nsGkAtoms::pt)
|
||||
unitType = SVG_LENGTHTYPE_PT;
|
||||
else if (unitAtom == nsGkAtoms::pc)
|
||||
unitType = SVG_LENGTHTYPE_PC;
|
||||
else if (unitAtom == nsGkAtoms::em)
|
||||
unitType = SVG_LENGTHTYPE_EMS;
|
||||
else if (unitAtom == nsGkAtoms::ex)
|
||||
unitType = SVG_LENGTHTYPE_EXS;
|
||||
else if (unitAtom == nsGkAtoms::percentage)
|
||||
unitType = SVG_LENGTHTYPE_PERCENTAGE;
|
||||
}
|
||||
if (IsValidUnitType(unitType) && NS_FloatIsFinite(value)) {
|
||||
WillModify();
|
||||
mValueInSpecifiedUnits = value;
|
||||
mSpecifiedUnitType = unitType;
|
||||
DidModify();
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* void newValueSpecifiedUnits (in unsigned short unitType, in float valueInSpecifiedUnits); */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUnits)
|
||||
{
|
||||
NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
WillModify();
|
||||
mValueInSpecifiedUnits = valueInSpecifiedUnits;
|
||||
mSpecifiedUnitType = unitType;
|
||||
DidModify();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void convertToSpecifiedUnits (in unsigned short unitType); */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::ConvertToSpecifiedUnits(PRUint16 unitType)
|
||||
{
|
||||
if (!IsValidUnitType(unitType))
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
|
||||
WillModify();
|
||||
float valueInUserUnits;
|
||||
GetValue(&valueInUserUnits);
|
||||
mSpecifiedUnitType = unitType;
|
||||
SetValue(valueInUserUnits);
|
||||
DidModify();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGLength methods:
|
||||
NS_IMETHODIMP
|
||||
nsSVGLength::SetContext(nsIWeakReference *aContext, PRUint8 aCtxType)
|
||||
{
|
||||
mElement = aContext;
|
||||
mCtxType = aCtxType;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation helpers:
|
||||
|
||||
float nsSVGLength::mmPerPixel()
|
||||
{
|
||||
nsCOMPtr<nsIContent> element = do_QueryReferent(mElement);
|
||||
if (!element) {
|
||||
NS_WARNING("no context in mmPerPixel()");
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
nsSVGSVGElement *ctx = static_cast<nsSVGElement*>(element.get())->GetCtx();
|
||||
if (!ctx) {
|
||||
return 1e-4f; // some small value
|
||||
}
|
||||
|
||||
float mmPerPx = ctx->GetMMPerPx(mCtxType);
|
||||
|
||||
if (mmPerPx == 0.0f) {
|
||||
NS_ASSERTION(mmPerPx != 0.0f, "invalid mm/pixels");
|
||||
mmPerPx = 1e-4f; // some small value
|
||||
}
|
||||
|
||||
return mmPerPx;
|
||||
}
|
||||
|
||||
float nsSVGLength::AxisLength()
|
||||
{
|
||||
nsCOMPtr<nsIContent> element = do_QueryReferent(mElement);
|
||||
if (!element) {
|
||||
NS_WARNING("no context in AxisLength()");
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
nsSVGSVGElement *ctx = static_cast<nsSVGElement*>(element.get())->GetCtx();
|
||||
if (!ctx) {
|
||||
return 1e-20f; // some small value
|
||||
}
|
||||
|
||||
float d = ctx->GetLength(mCtxType);
|
||||
|
||||
if (d == 0.0f) {
|
||||
NS_WARNING("zero axis length");
|
||||
d = 1e-20f;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
float nsSVGLength::EmLength()
|
||||
{
|
||||
nsCOMPtr<nsIContent> element = do_QueryReferent(mElement);
|
||||
return nsSVGUtils::GetFontSize(element->AsElement());
|
||||
}
|
||||
|
||||
float nsSVGLength::ExLength()
|
||||
{
|
||||
nsCOMPtr<nsIContent> element = do_QueryReferent(mElement);
|
||||
return nsSVGUtils::GetFontXHeight(element->AsElement());
|
||||
}
|
||||
|
||||
PRBool nsSVGLength::IsValidUnitType(PRUint16 unit)
|
||||
{
|
||||
if (unit > SVG_LENGTHTYPE_UNKNOWN && unit <= SVG_LENGTHTYPE_PC)
|
||||
return PR_TRUE;
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* 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_SVGLENGTH_H__
|
||||
#define __NS_SVGLENGTH_H__
|
||||
|
||||
#include "nsISVGLength.h"
|
||||
#include "nsAString.h"
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLength(nsISVGLength** result,
|
||||
float value=0.0f,
|
||||
PRUint16 unit=nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLength(nsISVGLength** result,
|
||||
const nsAString &value);
|
||||
|
||||
// XXX we'll need this prototype-based stuff to support unsetting:
|
||||
//nsresult NS_NewSVGLength(nsIDOMSVGLength** result,
|
||||
// nsIDOMSVGLength* prototype);
|
||||
|
||||
|
||||
#endif //__NS_SVGLENGTH_H__
|
|
@ -1,407 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* 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 "nsSVGLengthList.h"
|
||||
#include "nsSVGLength.h"
|
||||
#include "nsSVGValue.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsSVGSVGElement.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGLengthList
|
||||
|
||||
class nsSVGLengthList : public nsIDOMSVGLengthList,
|
||||
public nsSVGValue,
|
||||
public nsISVGValueObserver
|
||||
{
|
||||
protected:
|
||||
friend nsresult NS_NewSVGLengthList(nsIDOMSVGLengthList** result,
|
||||
nsSVGElement *aContext,
|
||||
PRUint8 aCtxType);
|
||||
|
||||
nsSVGLengthList(nsSVGElement *aContext, PRUint8 aCtxType);
|
||||
~nsSVGLengthList();
|
||||
// void Init();
|
||||
|
||||
public:
|
||||
// nsISupports interface:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIDOMSVGLengthList interface:
|
||||
NS_DECL_NSIDOMSVGLENGTHLIST
|
||||
|
||||
// remainder of nsISVGValue interface:
|
||||
NS_IMETHOD SetValueString(const nsAString& aValue);
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
// nsISVGValueObserver interface:
|
||||
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
|
||||
modificationType aModType);
|
||||
NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
|
||||
modificationType aModType);
|
||||
|
||||
// nsISupportsWeakReference
|
||||
// implementation inherited from nsSupportsWeakReference
|
||||
|
||||
protected:
|
||||
// implementation helpers:
|
||||
nsISVGLength* ElementAt(PRInt32 index);
|
||||
void AppendElement(nsISVGLength* aElement);
|
||||
void RemoveElementAt(PRInt32 index);
|
||||
void InsertElementAt(nsISVGLength* aElement, PRInt32 index);
|
||||
|
||||
void ReleaseLengths();
|
||||
|
||||
nsAutoTArray<nsISVGLength*, 1> mLengths;
|
||||
nsWeakPtr mContext; // needs to be weak to avoid reference loop
|
||||
PRUint8 mCtxType;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
nsSVGLengthList::nsSVGLengthList(nsSVGElement *aContext, PRUint8 aCtxType)
|
||||
: mCtxType(aCtxType)
|
||||
{
|
||||
mContext = do_GetWeakReference(static_cast<nsGenericElement*>(aContext));
|
||||
}
|
||||
|
||||
nsSVGLengthList::~nsSVGLengthList()
|
||||
{
|
||||
ReleaseLengths();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods:
|
||||
|
||||
NS_IMPL_ADDREF(nsSVGLengthList)
|
||||
NS_IMPL_RELEASE(nsSVGLengthList)
|
||||
|
||||
DOMCI_DATA(SVGLengthList, nsSVGLengthList)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsSVGLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGValue methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::SetValueString(const nsAString& aValue)
|
||||
{
|
||||
WillModify();
|
||||
|
||||
ReleaseLengths();
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
char* str;
|
||||
str = ToNewCString(aValue);
|
||||
|
||||
char* rest = str;
|
||||
char* token;
|
||||
const char* delimiters = ",\x20\x9\xD\xA";
|
||||
|
||||
while ((token = nsCRT::strtok(rest, delimiters, &rest))) {
|
||||
nsCOMPtr<nsISVGLength> length;
|
||||
NS_NewSVGLength(getter_AddRefs(length), NS_ConvertASCIItoUTF16(token));
|
||||
if (!length) {
|
||||
rv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
break;
|
||||
}
|
||||
AppendElement(length);
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
|
||||
DidModify();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::GetValueString(nsAString& aValue)
|
||||
{
|
||||
aValue.Truncate();
|
||||
|
||||
PRUint32 count = mLengths.Length();
|
||||
|
||||
if (count == 0) return NS_OK;
|
||||
|
||||
PRUint32 i = 0;
|
||||
|
||||
while (1) {
|
||||
nsISVGLength* length = ElementAt(i);
|
||||
nsCOMPtr<nsISVGValue> val = do_QueryInterface(length);
|
||||
NS_ASSERTION(val, "length doesn't implement required interface");
|
||||
if (!val) continue;
|
||||
nsAutoString str;
|
||||
val->GetValueString(str);
|
||||
aValue.Append(str);
|
||||
|
||||
if (++i >= count) break;
|
||||
|
||||
aValue.AppendLiteral(" ");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGLengthList methods:
|
||||
|
||||
/* readonly attribute unsigned long numberOfItems; */
|
||||
NS_IMETHODIMP nsSVGLengthList::GetNumberOfItems(PRUint32 *aNumberOfItems)
|
||||
{
|
||||
*aNumberOfItems = mLengths.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void clear (); */
|
||||
NS_IMETHODIMP nsSVGLengthList::Clear()
|
||||
{
|
||||
WillModify();
|
||||
ReleaseLengths();
|
||||
DidModify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLength initialize (in nsIDOMSVGLength newItem); */
|
||||
NS_IMETHODIMP nsSVGLengthList::Initialize(nsIDOMSVGLength *newItem,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
if (!newItem) {
|
||||
*_retval = nsnull;
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
}
|
||||
Clear();
|
||||
return AppendItem(newItem, _retval);
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLength getItem (in unsigned long index); */
|
||||
NS_IMETHODIMP nsSVGLengthList::GetItem(PRUint32 index, nsIDOMSVGLength **_retval)
|
||||
{
|
||||
if (index >= mLengths.Length()) {
|
||||
*_retval = nsnull;
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
*_retval = ElementAt(index);
|
||||
NS_ADDREF(*_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLength insertItemBefore (in nsIDOMSVGLength newItem, in unsigned long index); */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
|
||||
PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
// null check when implementing - this method can be used by scripts!
|
||||
// if (!newItem)
|
||||
// return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
|
||||
NS_NOTYETIMPLEMENTED("nsSVGLengthList::InsertItemBefore");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLength replaceItem (in nsIDOMSVGLength newItem, in unsigned long index); */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
|
||||
PRUint32 index,
|
||||
nsIDOMSVGLength **_retval)
|
||||
{
|
||||
// null check when implementing - this method can be used by scripts!
|
||||
// if (!newItem)
|
||||
// return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
|
||||
NS_NOTYETIMPLEMENTED("nsSVGLengthList::ReplaceItem");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLengthList removeItem (in unsigned long index); */
|
||||
NS_IMETHODIMP nsSVGLengthList::RemoveItem(PRUint32 index, nsIDOMSVGLength **_retval)
|
||||
{
|
||||
if (index >= mLengths.Length()) {
|
||||
*_retval = nsnull;
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
*_retval = ElementAt(index);
|
||||
NS_ADDREF(*_retval);
|
||||
WillModify();
|
||||
RemoveElementAt(index);
|
||||
DidModify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGLengthList appendItem (in nsIDOMSVGLengthList newItem); */
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::AppendItem(nsIDOMSVGLength *newItem, nsIDOMSVGLength **_retval)
|
||||
{
|
||||
nsCOMPtr<nsISVGLength> length = do_QueryInterface(newItem);
|
||||
if (!length) {
|
||||
*_retval = nsnull;
|
||||
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
||||
}
|
||||
AppendElement(length);
|
||||
|
||||
*_retval = newItem;
|
||||
NS_ADDREF(*_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGValueObserver methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::WillModifySVGObservable(nsISVGValue* observable,
|
||||
modificationType aModType)
|
||||
{
|
||||
WillModify(aModType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGLengthList::DidModifySVGObservable(nsISVGValue* observable,
|
||||
modificationType aModType)
|
||||
{
|
||||
DidModify(aModType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation helpers
|
||||
|
||||
void
|
||||
nsSVGLengthList::ReleaseLengths()
|
||||
{
|
||||
WillModify();
|
||||
PRUint32 count = mLengths.Length();
|
||||
for (PRUint32 i = 0; i < count; ++i) {
|
||||
nsISVGLength* length = ElementAt(i);
|
||||
length->SetContext(nsnull, 0);
|
||||
NS_REMOVE_SVGVALUE_OBSERVER(length);
|
||||
NS_RELEASE(length);
|
||||
}
|
||||
mLengths.Clear();
|
||||
DidModify();
|
||||
}
|
||||
|
||||
nsISVGLength*
|
||||
nsSVGLengthList::ElementAt(PRInt32 index)
|
||||
{
|
||||
return mLengths.ElementAt(index);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLengthList::AppendElement(nsISVGLength* aElement)
|
||||
{
|
||||
WillModify();
|
||||
NS_ADDREF(aElement);
|
||||
|
||||
// The SVG specs state that 'if newItem is already in a list, it
|
||||
// is removed from its previous list before it is inserted into this
|
||||
// list':
|
||||
// aElement->SetListOwner(this);
|
||||
|
||||
aElement->SetContext(mContext, mCtxType);
|
||||
mLengths.AppendElement(aElement);
|
||||
NS_ADD_SVGVALUE_OBSERVER(aElement);
|
||||
DidModify();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLengthList::RemoveElementAt(PRInt32 index)
|
||||
{
|
||||
WillModify();
|
||||
nsISVGLength* length = ElementAt(index);
|
||||
NS_ASSERTION(length, "null length");
|
||||
NS_REMOVE_SVGVALUE_OBSERVER(length);
|
||||
mLengths.RemoveElementAt(index);
|
||||
NS_RELEASE(length);
|
||||
DidModify();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLengthList::InsertElementAt(nsISVGLength* aElement, PRInt32 index)
|
||||
{
|
||||
WillModify();
|
||||
NS_ADDREF(aElement);
|
||||
|
||||
// The SVG specs state that 'if newItem is already in a list, it
|
||||
// is removed from its previous list before it is inserted into this
|
||||
// list':
|
||||
// aElement->SetListOwner(this);
|
||||
|
||||
aElement->SetContext(mContext, mCtxType);
|
||||
|
||||
mLengths.InsertElementAt(index, aElement);
|
||||
NS_ADD_SVGVALUE_OBSERVER(aElement);
|
||||
DidModify();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Exported creation functions:
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLengthList(nsIDOMSVGLengthList** result, nsSVGElement *aContext, PRUint8 aCtxType)
|
||||
{
|
||||
*result = nsnull;
|
||||
|
||||
nsSVGLengthList* lengthList = new nsSVGLengthList(aContext, aCtxType);
|
||||
if (!lengthList) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(lengthList);
|
||||
|
||||
*result = lengthList;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/* -*- 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
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* 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_SVGLENGTHLIST_H__
|
||||
#define __NS_SVGLENGTHLIST_H__
|
||||
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
nsresult
|
||||
NS_NewSVGLengthList(nsIDOMSVGLengthList** result, nsSVGElement *aContext, PRUint8 aCtxType);
|
||||
|
||||
#endif //__NS_SVGLENGTHLIST_H__
|
|
@ -39,7 +39,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSVGLength.h"
|
||||
#include "DOMSVGLength.h"
|
||||
#include "nsSVGAngle.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPresShell.h"
|
||||
|
@ -655,7 +655,8 @@ nsSVGSVGElement::CreateSVGNumber(nsIDOMSVGNumber **_retval)
|
|||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::CreateSVGLength(nsIDOMSVGLength **_retval)
|
||||
{
|
||||
return NS_NewSVGLength(reinterpret_cast<nsISVGLength**>(_retval));
|
||||
NS_IF_ADDREF(*_retval = new DOMSVGLength());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGAngle createSVGAngle (); */
|
||||
|
|
|
@ -115,7 +115,7 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGStopElement)
|
|||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGStopElement methods
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedLengthList x; */
|
||||
/* readonly attribute nsIDOMSVGAnimatedNumber offset; */
|
||||
NS_IMETHODIMP nsSVGStopElement::GetOffset(nsIDOMSVGAnimatedNumber * *aOffset)
|
||||
{
|
||||
return mOffset.ToDOMAnimatedNumber(aOffset,this);
|
||||
|
|
|
@ -44,11 +44,14 @@
|
|||
#include "nsSVGTextPositioningElement.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsSVGLengthList.h"
|
||||
#include "nsSVGAnimatedLengthList.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsSVGNumberList.h"
|
||||
#include "nsSVGAnimatedNumberList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef nsSVGGraphicElement nsSVGTextElementBase;
|
||||
|
||||
/**
|
||||
|
@ -96,11 +99,14 @@ protected:
|
|||
return do_QueryFrame(GetPrimaryFrame(Flush_Layout));
|
||||
}
|
||||
|
||||
virtual LengthListAttributesInfo GetLengthListInfo();
|
||||
|
||||
// nsIDOMSVGTextPositioning properties:
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mX;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mY;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mdX;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mdY;
|
||||
|
||||
enum { X, Y, DX, DY };
|
||||
SVGAnimatedLengthList mLengthListAttributes[4];
|
||||
static LengthListInfo sLengthListInfo[4];
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedNumberList> mRotate;
|
||||
};
|
||||
|
||||
|
@ -139,54 +145,6 @@ nsSVGTextElement::Init()
|
|||
nsresult rv = nsSVGTextElementBase::Init();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::x, #IMPLIED attrib: x
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::X);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mX),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::x, mX);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::y, #IMPLIED attrib: y
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::Y);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mY),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::y, mY);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::dx, #IMPLIED attrib: dx
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::X);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mdX),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::dx, mdX);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::dy, #IMPLIED attrib: dy
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::Y);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mdY),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::dy, mdY);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::rotate, #IMPLIED attrib: rotate
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGNumberList> numberList;
|
||||
|
@ -222,8 +180,8 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGTextElement)
|
|||
NS_IMETHODIMP
|
||||
nsSVGTextElement::GetX(nsIDOMSVGAnimatedLengthList * *aX)
|
||||
{
|
||||
*aX = mX;
|
||||
NS_IF_ADDREF(*aX);
|
||||
*aX = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[X],
|
||||
this, X, nsSVGUtils::X).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -231,8 +189,8 @@ nsSVGTextElement::GetX(nsIDOMSVGAnimatedLengthList * *aX)
|
|||
NS_IMETHODIMP
|
||||
nsSVGTextElement::GetY(nsIDOMSVGAnimatedLengthList * *aY)
|
||||
{
|
||||
*aY = mY;
|
||||
NS_IF_ADDREF(*aY);
|
||||
*aY = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[Y],
|
||||
this, Y, nsSVGUtils::Y).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -240,8 +198,8 @@ nsSVGTextElement::GetY(nsIDOMSVGAnimatedLengthList * *aY)
|
|||
NS_IMETHODIMP
|
||||
nsSVGTextElement::GetDx(nsIDOMSVGAnimatedLengthList * *aDx)
|
||||
{
|
||||
*aDx = mdX;
|
||||
NS_IF_ADDREF(*aDx);
|
||||
*aDx = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[DX],
|
||||
this, DX, nsSVGUtils::X).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -249,8 +207,8 @@ nsSVGTextElement::GetDx(nsIDOMSVGAnimatedLengthList * *aDx)
|
|||
NS_IMETHODIMP
|
||||
nsSVGTextElement::GetDy(nsIDOMSVGAnimatedLengthList * *aDy)
|
||||
{
|
||||
*aDy = mdY;
|
||||
NS_IF_ADDREF(*aDy);
|
||||
*aDy = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[DY],
|
||||
this, DY, nsSVGUtils::Y).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -417,3 +375,22 @@ nsSVGTextElement::IsAttributeMapped(const nsIAtom* name) const
|
|||
return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
|
||||
nsSVGTextElementBase::IsAttributeMapped(name);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGElement methods
|
||||
|
||||
nsSVGElement::LengthListInfo nsSVGTextElement::sLengthListInfo[4] =
|
||||
{
|
||||
{ &nsGkAtoms::x, nsSVGUtils::X, PR_FALSE },
|
||||
{ &nsGkAtoms::y, nsSVGUtils::Y, PR_FALSE },
|
||||
{ &nsGkAtoms::dx, nsSVGUtils::X, PR_TRUE },
|
||||
{ &nsGkAtoms::dy, nsSVGUtils::Y, PR_TRUE }
|
||||
};
|
||||
|
||||
nsSVGElement::LengthListAttributesInfo
|
||||
nsSVGTextElement::GetLengthListInfo()
|
||||
{
|
||||
return LengthListAttributesInfo(mLengthListAttributes, sLengthListInfo,
|
||||
NS_ARRAY_LENGTH(sLengthListInfo));
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,14 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsSVGTextPositioningElement.h"
|
||||
#include "nsSVGAnimatedLengthList.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
#include "DOMSVGAnimatedLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsSVGAnimatedNumberList.h"
|
||||
#include "nsSVGLengthList.h"
|
||||
#include "nsSVGNumberList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsresult
|
||||
nsSVGTextPositioningElement::Init()
|
||||
{
|
||||
|
@ -47,54 +50,6 @@ nsSVGTextPositioningElement::Init()
|
|||
|
||||
// Create mapped properties:
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::x, #IMPLIED attrib: x
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::X);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mX),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::x, mX);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::y, #IMPLIED attrib: y
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::Y);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mY),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::y, mY);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::dx, #IMPLIED attrib: dx
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::X);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mdX),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::dx, mdX);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::dy, #IMPLIED attrib: dy
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> lengthList;
|
||||
rv = NS_NewSVGLengthList(getter_AddRefs(lengthList), this, nsSVGUtils::Y);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = NS_NewSVGAnimatedLengthList(getter_AddRefs(mdY),
|
||||
lengthList);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsGkAtoms::dy, mdY);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// DOM property: nsIDOMSVGTextPositioningElement::rotate, #IMPLIED attrib: rotate
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGNumberList> numberList;
|
||||
|
@ -110,38 +65,54 @@ nsSVGTextPositioningElement::Init()
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsSVGElement::LengthListInfo nsSVGTextPositioningElement::sLengthListInfo[4] =
|
||||
{
|
||||
{ &nsGkAtoms::x, nsSVGUtils::X, PR_FALSE },
|
||||
{ &nsGkAtoms::y, nsSVGUtils::Y, PR_FALSE },
|
||||
{ &nsGkAtoms::dx, nsSVGUtils::X, PR_TRUE },
|
||||
{ &nsGkAtoms::dy, nsSVGUtils::Y, PR_TRUE }
|
||||
};
|
||||
|
||||
nsSVGElement::LengthListAttributesInfo
|
||||
nsSVGTextPositioningElement::GetLengthListInfo()
|
||||
{
|
||||
return LengthListAttributesInfo(mLengthListAttributes, sLengthListInfo,
|
||||
NS_ARRAY_LENGTH(sLengthListInfo));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGTextPositioningElement methods
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedLengthList x; */
|
||||
NS_IMETHODIMP nsSVGTextPositioningElement::GetX(nsIDOMSVGAnimatedLengthList * *aX)
|
||||
{
|
||||
*aX = mX;
|
||||
NS_IF_ADDREF(*aX);
|
||||
*aX = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[X],
|
||||
this, X, nsSVGUtils::X).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedLengthList y; */
|
||||
NS_IMETHODIMP nsSVGTextPositioningElement::GetY(nsIDOMSVGAnimatedLengthList * *aY)
|
||||
{
|
||||
*aY = mY;
|
||||
NS_IF_ADDREF(*aY);
|
||||
*aY = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[Y],
|
||||
this, Y, nsSVGUtils::Y).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedLengthList dx; */
|
||||
NS_IMETHODIMP nsSVGTextPositioningElement::GetDx(nsIDOMSVGAnimatedLengthList * *aDx)
|
||||
{
|
||||
*aDx = mdX;
|
||||
NS_IF_ADDREF(*aDx);
|
||||
*aDx = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[DX],
|
||||
this, DX, nsSVGUtils::X).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGAnimatedLengthList dy; */
|
||||
NS_IMETHODIMP nsSVGTextPositioningElement::GetDy(nsIDOMSVGAnimatedLengthList * *aDy)
|
||||
{
|
||||
*aDy = mdY;
|
||||
NS_IF_ADDREF(*aDy);
|
||||
*aDy = DOMSVGAnimatedLengthList::GetDOMWrapper(&mLengthListAttributes[DY],
|
||||
this, DY, nsSVGUtils::Y).get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,9 +40,14 @@
|
|||
#include "nsSVGTextContentElement.h"
|
||||
#include "nsIDOMSVGAnimatedLengthList.h"
|
||||
#include "nsIDOMSVGAnimatedNumberList.h"
|
||||
#include "SVGAnimatedLengthList.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
namespace mozilla {
|
||||
class SVGAnimatedLengthList;
|
||||
}
|
||||
|
||||
typedef nsSVGTextContentElement nsSVGTextPositioningElementBase;
|
||||
|
||||
/**
|
||||
|
@ -63,11 +68,14 @@ protected:
|
|||
|
||||
nsresult Init();
|
||||
|
||||
virtual LengthListAttributesInfo GetLengthListInfo();
|
||||
|
||||
// nsIDOMSVGTextPositioning properties:
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mX;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mY;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mdX;
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> mdY;
|
||||
|
||||
enum { X, Y, DX, DY };
|
||||
SVGAnimatedLengthList mLengthListAttributes[4];
|
||||
static LengthListInfo sLengthListInfo[4];
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedNumberList> mRotate;
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ _TEST_FILES = \
|
|||
test_scientific.html \
|
||||
scientific-helper.svg \
|
||||
test_SVGStyleElement.xhtml \
|
||||
test_SVGxxxList.xhtml \
|
||||
test_switch.xhtml \
|
||||
switch-helper.svg \
|
||||
test_text.html \
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,23 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<text transform="translate(20, 20)"
|
||||
x="20 10mm 3pc 72pt 2em 3% 1ex"
|
||||
dy="20 10mm 3pc 36pt 2em 3% 1ex 1">ABCDEFGH
|
||||
</text>
|
||||
|
||||
<text transform="translate(120, 20)"
|
||||
x="20 10mm 3pc 72pt 2em 3% 1ex"
|
||||
dy="20 10mm 3pc 36pt 2em 3% 1ex">IJKLMNOP
|
||||
</text>
|
||||
|
||||
<text transform="translate(220, 20)"
|
||||
x="20 10mm 3pc 72pt 2em 3% 1ex"
|
||||
dy="20 10mm 3pc 36pt 2em 3% 1ex 1">QRSTUVWX
|
||||
</text>
|
||||
|
||||
<text transform="translate(320, 20)"
|
||||
x="20 10mm 3pc 72pt 2em 3% 1ex"
|
||||
dy="20 10mm 3pc 36pt 2em 3% 1ex">YZ123456
|
||||
</text>
|
||||
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 612 B |
|
@ -0,0 +1,179 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="reftest-wait"
|
||||
onload="setTimeAndSnapshot(5, true)">
|
||||
<title>Test animation of the <length-list> attributes on the 'text' element</title>
|
||||
<script xlink:href="smil-util.js" type="text/javascript"/>
|
||||
|
||||
<style type="text/css">
|
||||
:root { font-size: 16px; } /* see comment below - sets 1em == 16px */
|
||||
</style>
|
||||
|
||||
<!-- If we start getting random orange on this test, see:
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c34
|
||||
-->
|
||||
|
||||
<!-- One of the things that this file tests is animation between lengths
|
||||
of _different unit_. One difficulty this creates is knowing the
|
||||
values to use in the reference file. For example, what length should
|
||||
be used in the reference to comparing against an animation that's mid
|
||||
way between 50px and 10in? The SMIL engine will convert the start
|
||||
length to the unit of the end length and then interpolate, but the
|
||||
number of inches in 50px is not always the same, so we can't fix how
|
||||
many inches is midway between 50px and 10in in the reference file. To
|
||||
get around this problem this test mainly pairs different units with a
|
||||
knows, fixed, relationship. For example, animating between cm and mm,
|
||||
or between 'in' and pt (72 pt/in) or between 'in' and pc (6 pc/in).
|
||||
Note that we can animate between px and em by fixing the relationship
|
||||
between these units by setting the CSS 'font-size' property to a fixed
|
||||
number of px units as we've done above.
|
||||
|
||||
The problem with only testing pairs with a fixed relationship is that
|
||||
implementations may only implement interpolation between those pairs
|
||||
because it's easy. To test interpolation between pairs of units
|
||||
without a fixed relationship we use another strategy: we animate from
|
||||
zero of the start unit. Since zero is zero regardless of the unit, we
|
||||
then know what to use in the reference. In theory implementations might
|
||||
specialize for zero, but that's unlikely (hopefully!).
|
||||
|
||||
(An alternative would be to only test end points of the animation, but
|
||||
implementations may use discrete animation rather than interpolation
|
||||
when lengths of different units are encountered, so that would be a bad
|
||||
approach.)
|
||||
|
||||
(Another better alternative would be to use
|
||||
SVGLength.convertToSpecifiedUnits() in the reference file to figure out
|
||||
the conversion of the start unit and set values in the reference file
|
||||
dynamically.)
|
||||
-->
|
||||
|
||||
<!-- Another thing that this file test is animation between lists
|
||||
of _different length_. One implementation strategy when faced with such
|
||||
an animation is to pad the shorter list with zeros for the purposes of
|
||||
animation. This works exactly as you would hope in the case of the
|
||||
<text> element's 'dx' and 'dy' attributes, since for those attributes
|
||||
lengths are offsets from the coordinate at which respective glyph's
|
||||
would otherwise be positioned. In other words, appending a list of
|
||||
zeros to any 'dx' or 'dy' attribute will never have an affect on
|
||||
rendering. However, in the case of 'x' and 'y' attributes on <text>,
|
||||
any lengths given are distances from zero along the relevant axis of
|
||||
the current coordinate system, and zero is not likely to be the
|
||||
position that all glyphs would otherwise be given. Their position will
|
||||
actually depend on CSS parameters, the implementation's text layout
|
||||
algorithm, and the layout of the characters that came before it. Hence
|
||||
zero padding any 'x' or 'y' attribute will likely drastically alter
|
||||
the rendering of the text, and in the case of animation would cause
|
||||
glyphs to animate from/to zero in their coordinate system instead of
|
||||
from/to their natural position. Clearly this is neither what authors
|
||||
would expect, or want, so Mozilla currently disallows animation of 'x'
|
||||
and 'y' if lists of different length are encountered to prevent content
|
||||
being created that relies on such undesirable behavior.
|
||||
|
||||
Ideally the implementation would provide the SMIL engine with the
|
||||
natural position of each glyph so that it can animate from/to those
|
||||
positions. That's tricky, but we do have a bug open to try and
|
||||
implement that. See:
|
||||
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=573431
|
||||
-->
|
||||
|
||||
<!-- Test calcMode="linear". -->
|
||||
|
||||
<text transform="translate(20, 20)"
|
||||
x="10px 0.5cm 0.25in 0.5in 16px 0cm 0%">ABCDEFGH
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 72pt 2em 3% 1ex". -->
|
||||
<animate attributeName="x"
|
||||
calcMode="linear"
|
||||
begin="0s" dur="15s"
|
||||
to="40 20mm 6pc 144pt 4em 9% 3ex"
|
||||
fill="freeze"/>
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 36pt 2em 3% 1ex 1".
|
||||
Note that the 'to' list has one extra list item on purpose! -->
|
||||
<animate attributeName="dy"
|
||||
calcMode="linear"
|
||||
begin="0s" dur="15s"
|
||||
from="10px 0.5cm 0.25in 0.25in 16px 0cm 0%"
|
||||
to="40 20mm 6pc 72pt 4em 9% 3ex 3"
|
||||
fill="freeze"/>
|
||||
</text>
|
||||
|
||||
|
||||
<!-- Test 'by' animation. -->
|
||||
|
||||
<text transform="translate(120, 20)"
|
||||
x="10px 0.5cm 0.25in 0.5in 16px 0cm 0%">IJKLMNOP
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 72pt 2em 3% 1ex". -->
|
||||
<animate attributeName="x"
|
||||
calcMode="linear"
|
||||
begin="0s" dur="15s"
|
||||
by="30 15mm 4.5pc 108pt 3em 9% 3ex"
|
||||
fill="freeze"/>
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 36pt 2em 3% 1ex".
|
||||
Note that the 'from' list is essentially zero length! -->
|
||||
<animate attributeName="dy"
|
||||
calcMode="linear"
|
||||
begin="0s" dur="15s"
|
||||
by="60 30mm 9pc 108pt 6em 9% 3ex"
|
||||
fill="freeze"/>
|
||||
</text>
|
||||
|
||||
|
||||
<!-- Test calcMode="paced". It doesn't make a lot of sense to use paced
|
||||
animation with a length list, but since we support it, we test it.
|
||||
-->
|
||||
|
||||
<text transform="translate(220, 20)">QRSTUVWX
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 72pt 2em 3% 1ex". -->
|
||||
<animate attributeName="x"
|
||||
calcMode="paced"
|
||||
begin="0s" dur="15s"
|
||||
values="10px 0.5cm 0.25in 0.5in 16px 0cm 0%;
|
||||
30 15mm 4.5pc 108pt 3em 6% 2ex;
|
||||
40 20mm 6pc 144pt 4em 9% 3ex"
|
||||
fill="freeze"/>
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 36pt 2em 3% 1ex 1".
|
||||
Note that the 'to' lists have one extra list item on purpose! -->
|
||||
<animate attributeName="dy"
|
||||
calcMode="paced"
|
||||
begin="0s" dur="15s"
|
||||
values="10px 0.5cm 0.25in 0.25in 16px 0cm 0%;
|
||||
30 15mm 4.5pc 54pt 3em 6% 2ex 2;
|
||||
40 20mm 6pc 72pt 4em 9% 3ex 3"
|
||||
fill="freeze"/>
|
||||
</text>
|
||||
|
||||
|
||||
<!-- Test calcMode="discrete". In this case SMIL treats the 'from' and 'to'
|
||||
as two discrete values to jump between. Some authors may expect
|
||||
discrete animation to jump from integer to integer in the unit of the
|
||||
list item in question (or the unit of the 'to' item if the units of
|
||||
corresponding 'from' and 'to' items differ), but that's not the case.
|
||||
-->
|
||||
|
||||
<text transform="translate(320, 20)">YZ123456
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 72pt 2em 3% 1ex". -->
|
||||
<animate attributeName="x"
|
||||
calcMode="discrete"
|
||||
begin="0s" dur="10s"
|
||||
from="10px 0.5cm 0.25in 0.5in 16px 0cm 0%"
|
||||
to="20 10mm 3pc 72pt 2em 3% 1ex"
|
||||
fill="freeze"/>
|
||||
|
||||
<!-- At 5s the animVal should be "20 10mm 3pc 36pt 2em 3% 1ex".
|
||||
Note that the 'to' list has one extra list item on purpose! -->
|
||||
<animate attributeName="dy"
|
||||
calcMode="discrete"
|
||||
begin="0s" dur="10.1s"
|
||||
from="20 10mm 3pc 36pt 2em 3% 1ex"
|
||||
to="40px 2cm 1in 1in 16px 0cm 0% 3"
|
||||
fill="freeze"/>
|
||||
</text>
|
||||
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 7.9 KiB |
|
@ -136,6 +136,8 @@ fails == anim-strokecolor-1.svg anim-standard-ref.svg # bug 436296
|
|||
== anim-targethref-8.svg anim-standard-ref.svg
|
||||
== anim-targethref-9.svg anim-standard-ref.svg
|
||||
|
||||
== anim-text-x-y-dx-dy-01.svg anim-text-x-y-dx-dy-01-ref.svg
|
||||
|
||||
== anim-width-done-1a.svg anim-standard-ref.svg
|
||||
== anim-width-done-1b.svg anim-standard-ref.svg
|
||||
|
||||
|
|
|
@ -40,11 +40,13 @@
|
|||
#define __NS_ISVGGLYPHFRAGMENTLEAF_H__
|
||||
|
||||
#include "nsISVGGlyphFragmentNode.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
|
||||
class nsIDOMSVGPoint;
|
||||
class nsIDOMSVGRect;
|
||||
class nsSVGTextPathFrame;
|
||||
namespace mozilla {
|
||||
class SVGUserUnitList;
|
||||
}
|
||||
|
||||
class nsISVGGlyphFragmentLeaf : public nsISVGGlyphFragmentNode
|
||||
{
|
||||
|
@ -62,8 +64,7 @@ public:
|
|||
NS_IMETHOD_(nsSVGTextPathFrame*) FindTextPathParent()=0;
|
||||
NS_IMETHOD_(PRBool) IsStartOfChunk()=0; // == is new absolutely positioned chunk.
|
||||
|
||||
NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetX()=0;
|
||||
NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetY()=0;
|
||||
NS_IMETHOD_(void) GetXY(mozilla::SVGUserUnitList *aX, mozilla::SVGUserUnitList *aY)=0;
|
||||
NS_IMETHOD_(PRUint16) GetTextAnchor()=0;
|
||||
NS_IMETHOD_(PRBool) IsAbsolutelyPositioned()=0;
|
||||
};
|
||||
|
|
|
@ -43,12 +43,15 @@
|
|||
#include "nsSVGAElement.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "SVGLengthList.h"
|
||||
|
||||
// <a> elements can contain text. nsSVGGlyphFrames expect to have
|
||||
// a class derived from nsSVGTextContainerFrame as a parent. We
|
||||
// also need something that implements nsISVGGlyphFragmentNode to get
|
||||
// the text DOM to work.
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef nsSVGTSpanFrame nsSVGAFrameBase;
|
||||
|
||||
class nsSVGAFrame : public nsSVGAFrameBase
|
||||
|
@ -91,7 +94,11 @@ public:
|
|||
|
||||
// nsSVGContainerFrame methods:
|
||||
virtual gfxMatrix GetCanvasTM();
|
||||
|
||||
|
||||
// nsSVGTextContainerFrame methods:
|
||||
virtual void GetXY(mozilla::SVGUserUnitList *aX, mozilla::SVGUserUnitList *aY);
|
||||
virtual void GetDxDy(mozilla::SVGUserUnitList *aDx, mozilla::SVGUserUnitList *aDy);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
|
||||
};
|
||||
|
@ -183,3 +190,20 @@ nsSVGAFrame::GetCanvasTM()
|
|||
|
||||
return nsSVGUtils::ConvertSVGMatrixToThebes(mCanvasTM);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGTextContainerFrame methods:
|
||||
|
||||
void
|
||||
nsSVGAFrame::GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY)
|
||||
{
|
||||
aX->Clear();
|
||||
aY->Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGAFrame::GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy)
|
||||
{
|
||||
aDx->Clear();
|
||||
aDy->Clear();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include "nsILookAndFeel.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsIDOMSVGRect.h"
|
||||
#include "nsIDOMSVGPoint.h"
|
||||
|
@ -55,6 +55,8 @@
|
|||
#include "gfxPlatform.h"
|
||||
#include "gfxTextRunWordCache.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
struct CharacterPosition {
|
||||
gfxPoint pos;
|
||||
gfxFloat angle;
|
||||
|
@ -655,16 +657,6 @@ nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
|
|||
return !characterData.IsEmpty();
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
GetNumberOfLengthListItems(nsIDOMSVGLengthList *aList)
|
||||
{
|
||||
PRUint32 items = 0;
|
||||
if (aList) {
|
||||
aList->GetNumberOfItems(&items);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
GetNumberOfNumberListItems(nsIDOMSVGNumberList *aList)
|
||||
{
|
||||
|
@ -675,21 +667,6 @@ GetNumberOfNumberListItems(nsIDOMSVGNumberList *aList)
|
|||
return items;
|
||||
}
|
||||
|
||||
static float
|
||||
GetLengthListValue(nsIDOMSVGLengthList *aList, PRUint32 aIndex)
|
||||
{
|
||||
if (!aList) {
|
||||
return 0.0f;
|
||||
}
|
||||
nsCOMPtr<nsIDOMSVGLength> length;
|
||||
nsresult rv = aList->GetItem(aIndex, getter_AddRefs(length));
|
||||
float value = 0.0f;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
length->GetValue(&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static float
|
||||
GetNumberListValue(nsIDOMSVGNumberList *aList, PRUint32 aIndex)
|
||||
{
|
||||
|
@ -714,8 +691,8 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
|
||||
const gfxFloat radPerDeg = M_PI / 180.0;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGLengthList> dxList = GetDx();
|
||||
nsCOMPtr<nsIDOMSVGLengthList> dyList = GetDy();
|
||||
SVGUserUnitList dxList, dyList;
|
||||
GetDxDy(&dxList, &dyList);
|
||||
nsCOMPtr<nsIDOMSVGNumberList> rotateList = GetRotate();
|
||||
|
||||
PRBool rotateAllGlyphs = (GetNumberOfNumberListItems(rotateList) == 1);
|
||||
|
@ -746,8 +723,8 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
gfxFloat halfAdvance =
|
||||
mTextRun->GetAdvanceWidth(i, 1, nsnull)*aMetricsScale / 2.0;
|
||||
|
||||
pos.x += GetLengthListValue(dxList, i) * pathScale;
|
||||
pos.y += GetLengthListValue(dyList, i) * pathScale;
|
||||
pos.x += i < dxList.Length() ? dxList[i] * pathScale : 0.0;
|
||||
pos.y += i < dyList.Length() ? dyList[i] * pathScale : 0.0;
|
||||
|
||||
// check that we're within the path boundaries
|
||||
cp[i].draw = (pos.x + halfAdvance >= 0.0 &&
|
||||
|
@ -770,16 +747,16 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMSVGLengthList> xList = GetX();
|
||||
nsCOMPtr<nsIDOMSVGLengthList> yList = GetY();
|
||||
SVGUserUnitList xList, yList;
|
||||
GetXY(&xList, &yList);
|
||||
|
||||
PRUint32 xListCount = GetNumberOfLengthListItems(xList);
|
||||
PRUint32 yListCount = GetNumberOfLengthListItems(yList);
|
||||
PRUint32 xListCount = xList.Length();
|
||||
PRUint32 yListCount = yList.Length();
|
||||
|
||||
if (xListCount <= 1 &&
|
||||
yListCount <= 1 &&
|
||||
GetNumberOfLengthListItems(dxList) == 0 &&
|
||||
GetNumberOfLengthListItems(dyList) == 0 &&
|
||||
dxList.Length() == 0 &&
|
||||
dyList.Length() == 0 &&
|
||||
GetNumberOfNumberListItems(rotateList) == 0) {
|
||||
// simple text without individual positioning
|
||||
return PR_TRUE;
|
||||
|
@ -797,7 +774,7 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
|
||||
gfxFloat advance = mTextRun->GetAdvanceWidth(i, 1, nsnull)*aMetricsScale;
|
||||
if (xListCount > 1 && i < xListCount) {
|
||||
pos.x = GetLengthListValue(xList, i);
|
||||
pos.x = xList[i];
|
||||
// apply text-anchor to character
|
||||
if (anchor == NS_STYLE_TEXT_ANCHOR_MIDDLE)
|
||||
pos.x -= advance/2.0;
|
||||
|
@ -805,10 +782,10 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
pos.x -= advance;
|
||||
}
|
||||
if (yListCount > 1 && i < yListCount) {
|
||||
pos.y = GetLengthListValue(yList, i);
|
||||
pos.y = yList[i];
|
||||
}
|
||||
pos.x += GetLengthListValue(dxList, i);
|
||||
pos.y += GetLengthListValue(dyList, i);
|
||||
pos.x += i < dxList.Length() ? dxList[i] : 0.0;
|
||||
pos.y += i < dyList.Length() ? dyList[i] : 0.0;
|
||||
cp[i].pos = pos;
|
||||
pos.x += advance;
|
||||
cp[i].angle = rotateAllGlyphs ? overallGlyphRotation :
|
||||
|
@ -828,8 +805,9 @@ nsSVGGlyphFrame::GetSubStringAdvance(PRUint32 aCharnum,
|
|||
gfxFloat advance =
|
||||
mTextRun->GetAdvanceWidth(aCharnum, aFragmentChars, nsnull) * aMetricsScale;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGLengthList> dxlist = GetDx();
|
||||
PRUint32 dxcount = GetNumberOfLengthListItems(dxlist);
|
||||
SVGUserUnitList dxlist, notUsed;
|
||||
GetDxDy(&dxlist, ¬Used);
|
||||
PRUint32 dxcount = dxlist.Length();
|
||||
if (dxcount) {
|
||||
gfxFloat pathScale = 1.0;
|
||||
nsSVGTextPathFrame *textPath = FindTextPathParent();
|
||||
|
@ -838,7 +816,7 @@ nsSVGGlyphFrame::GetSubStringAdvance(PRUint32 aCharnum,
|
|||
if (dxcount > aFragmentChars)
|
||||
dxcount = aFragmentChars;
|
||||
for (PRUint32 i = aCharnum; i < dxcount; i++) {
|
||||
advance += GetLengthListValue(dxlist, i) * pathScale;
|
||||
advance += dxlist[i] * pathScale;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1044,20 +1022,20 @@ nsSVGGlyphFrame::SetGlyphPosition(gfxPoint *aPosition, PRBool aForceGlobalTransf
|
|||
if (textPath)
|
||||
pathScale = textPath->GetPathScale();
|
||||
|
||||
nsCOMPtr<nsIDOMSVGLengthList> dxList = GetDx();
|
||||
nsCOMPtr<nsIDOMSVGLengthList> dyList = GetDy();
|
||||
SVGUserUnitList dxList, dyList;
|
||||
GetDxDy(&dxList, &dyList);
|
||||
|
||||
PRUint32 dxcount = GetNumberOfLengthListItems(dxList);
|
||||
PRUint32 dxcount = dxList.Length();
|
||||
if (dxcount > strLength)
|
||||
dxcount = strLength;
|
||||
for (PRUint32 i = 0; i < dxcount; i++) {
|
||||
aPosition->x += GetLengthListValue(dxList, i) * pathScale;
|
||||
aPosition->x += dxList[i] * pathScale;
|
||||
}
|
||||
PRUint32 dycount = GetNumberOfLengthListItems(dyList);
|
||||
PRUint32 dycount = dyList.Length();
|
||||
if (dycount > strLength)
|
||||
dycount = strLength;
|
||||
for (PRUint32 i = 0; i < dycount; i++) {
|
||||
aPosition->y += GetLengthListValue(dyList, i) * pathScale;
|
||||
aPosition->y += dyList[i] * pathScale;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1173,44 +1151,22 @@ nsSVGGlyphFrame::IsStartOfChunk()
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
|
||||
nsSVGGlyphFrame::GetX()
|
||||
NS_IMETHODIMP_(void)
|
||||
nsSVGGlyphFrame::GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY)
|
||||
{
|
||||
nsSVGTextContainerFrame *containerFrame;
|
||||
containerFrame = static_cast<nsSVGTextContainerFrame *>(mParent);
|
||||
if (containerFrame)
|
||||
return containerFrame->GetX();
|
||||
return nsnull;
|
||||
containerFrame->GetXY(aX, aY);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
|
||||
nsSVGGlyphFrame::GetY()
|
||||
void
|
||||
nsSVGGlyphFrame::GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy)
|
||||
{
|
||||
nsSVGTextContainerFrame *containerFrame;
|
||||
containerFrame = static_cast<nsSVGTextContainerFrame *>(mParent);
|
||||
if (containerFrame)
|
||||
return containerFrame->GetY();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGGlyphFrame::GetDx()
|
||||
{
|
||||
nsSVGTextContainerFrame *containerFrame;
|
||||
containerFrame = static_cast<nsSVGTextContainerFrame *>(mParent);
|
||||
if (containerFrame)
|
||||
return containerFrame->GetDx();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGGlyphFrame::GetDy()
|
||||
{
|
||||
nsSVGTextContainerFrame *containerFrame;
|
||||
containerFrame = static_cast<nsSVGTextContainerFrame *>(mParent);
|
||||
if (containerFrame)
|
||||
return containerFrame->GetDy();
|
||||
return nsnull;
|
||||
containerFrame->GetDxDy(aDx, aDy);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGNumberList>
|
||||
|
|
|
@ -149,8 +149,7 @@ public:
|
|||
NS_IMETHOD_(nsSVGTextPathFrame*) FindTextPathParent();
|
||||
NS_IMETHOD_(PRBool) IsStartOfChunk(); // == is new absolutely positioned chunk.
|
||||
|
||||
NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetX();
|
||||
NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetY();
|
||||
NS_IMETHOD_(void) GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY);
|
||||
NS_IMETHOD_(PRUint16) GetTextAnchor();
|
||||
NS_IMETHOD_(PRBool) IsAbsolutelyPositioned();
|
||||
|
||||
|
@ -207,8 +206,7 @@ protected:
|
|||
float aMetricsScale);
|
||||
gfxFloat GetBaselineOffset(float aMetricsScale);
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList> GetDx();
|
||||
already_AddRefed<nsIDOMSVGLengthList> GetDy();
|
||||
virtual void GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy);
|
||||
already_AddRefed<nsIDOMSVGNumberList> GetRotate();
|
||||
|
||||
// Used to support GetBBoxContribution by making GetConvasTM use this as the
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#include "nsIDOMSVGAnimatedNumberList.h"
|
||||
#include "nsISVGGlyphFragmentLeaf.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "SVGLengthList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsQueryFrame methods
|
||||
|
@ -61,68 +64,21 @@ nsSVGTextContainerFrame::NotifyGlyphMetricsChange()
|
|||
textFrame->NotifyGlyphMetricsChange();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextContainerFrame::GetX()
|
||||
void
|
||||
nsSVGTextContainerFrame::GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY)
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement =
|
||||
do_QueryInterface(mContent);
|
||||
|
||||
if (!tpElement)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
|
||||
tpElement->GetX(getter_AddRefs(animLengthList));
|
||||
nsIDOMSVGLengthList *retval;
|
||||
animLengthList->GetAnimVal(&retval);
|
||||
return retval;
|
||||
static_cast<nsSVGElement*>(mContent)->
|
||||
GetAnimatedLengthListValues(aX, aY, nsnull);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextContainerFrame::GetY()
|
||||
void
|
||||
nsSVGTextContainerFrame::GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy)
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement =
|
||||
do_QueryInterface(mContent);
|
||||
|
||||
if (!tpElement)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
|
||||
tpElement->GetY(getter_AddRefs(animLengthList));
|
||||
nsIDOMSVGLengthList *retval;
|
||||
animLengthList->GetAnimVal(&retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextContainerFrame::GetDx()
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement =
|
||||
do_QueryInterface(mContent);
|
||||
|
||||
if (!tpElement)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
|
||||
tpElement->GetDx(getter_AddRefs(animLengthList));
|
||||
nsIDOMSVGLengthList *retval;
|
||||
animLengthList->GetAnimVal(&retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextContainerFrame::GetDy()
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement =
|
||||
do_QueryInterface(mContent);
|
||||
|
||||
if (!tpElement)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
|
||||
tpElement->GetDy(getter_AddRefs(animLengthList));
|
||||
nsIDOMSVGLengthList *retval;
|
||||
animLengthList->GetAnimVal(&retval);
|
||||
return retval;
|
||||
// SVGUserUnitList is lazy, so there's little overhead it getting the x
|
||||
// and y lists even though we ignore them.
|
||||
SVGUserUnitList xLengthList, yLengthList;
|
||||
static_cast<nsSVGElement*>(mContent)->
|
||||
GetAnimatedLengthListValues(&xLengthList, &yLengthList, aDx, aDy, nsnull);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGNumberList>
|
||||
|
|
|
@ -38,13 +38,14 @@
|
|||
#define NS_SVGTEXTCONTAINERFRAME_H
|
||||
|
||||
#include "nsSVGContainerFrame.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
#include "nsIDOMSVGNumberList.h"
|
||||
|
||||
class nsISVGGlyphFragmentNode;
|
||||
class nsISVGGlyphFragmentLeaf;
|
||||
|
||||
class nsSVGTextFrame;
|
||||
namespace mozilla {
|
||||
class SVGUserUnitList;
|
||||
}
|
||||
|
||||
class nsSVGTextContainerFrame : public nsSVGDisplayContainerFrame
|
||||
{
|
||||
|
@ -53,10 +54,8 @@ public:
|
|||
nsSVGDisplayContainerFrame(aContext) {}
|
||||
|
||||
void NotifyGlyphMetricsChange();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetX();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetY();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetDx();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetDy();
|
||||
virtual void GetXY(mozilla::SVGUserUnitList *aX, mozilla::SVGUserUnitList *aY);
|
||||
virtual void GetDxDy(mozilla::SVGUserUnitList *aDx, mozilla::SVGUserUnitList *aDy);
|
||||
virtual already_AddRefed<nsIDOMSVGNumberList> GetRotate();
|
||||
|
||||
public:
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "nsIDOMSVGTextElement.h"
|
||||
#include "nsSVGTextFrame.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIDOMSVGLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsIDOMSVGAnimatedNumber.h"
|
||||
#include "nsISVGGlyphFragmentNode.h"
|
||||
|
@ -54,6 +54,8 @@
|
|||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGGraphicElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
|
@ -291,23 +293,6 @@ nsSVGTextFrame::NotifyGlyphMetricsChange()
|
|||
UpdateGlyphPositioning(PR_FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
GetSingleValue(nsIDOMSVGLengthList *list, gfxFloat *val)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
PRUint32 count = 0;
|
||||
list->GetNumberOfItems(&count);
|
||||
if (count) {
|
||||
nsCOMPtr<nsIDOMSVGLength> length;
|
||||
list->GetItem(0, getter_AddRefs(length));
|
||||
float value;
|
||||
length->GetValue(&value);
|
||||
*val = value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGTextFrame::UpdateGlyphPositioning(PRBool aForceGlobalTransform)
|
||||
{
|
||||
|
@ -330,25 +315,16 @@ nsSVGTextFrame::UpdateGlyphPositioning(PRBool aForceGlobalTransform)
|
|||
|
||||
gfxPoint ctp(0.0, 0.0);
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> list = GetX();
|
||||
GetSingleValue(list, &ctp.x);
|
||||
}
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> list = GetY();
|
||||
GetSingleValue(list, &ctp.y);
|
||||
}
|
||||
SVGUserUnitList xLengthList, yLengthList;
|
||||
GetXY(&xLengthList, &yLengthList);
|
||||
if (xLengthList.Length() > 0) ctp.x = xLengthList[0];
|
||||
if (yLengthList.Length() > 0) ctp.y = yLengthList[0];
|
||||
|
||||
// loop over chunks
|
||||
while (firstFragment) {
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> list = firstFragment->GetX();
|
||||
GetSingleValue(list, &ctp.x);
|
||||
}
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGLengthList> list = firstFragment->GetY();
|
||||
GetSingleValue(list, &ctp.y);
|
||||
}
|
||||
firstFragment->GetXY(&xLengthList, &yLengthList);
|
||||
if (xLengthList.Length() > 0) ctp.x = xLengthList[0];
|
||||
if (yLengthList.Length() > 0) ctp.y = yLengthList[0];
|
||||
|
||||
// check for startOffset on textPath
|
||||
nsSVGTextPathFrame *textPath = firstFragment->FindTextPathParent();
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include "nsSVGPathElement.h"
|
||||
#include "nsSVGTextPathElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
|
@ -83,29 +85,20 @@ nsSVGTextPathFrame::GetType() const
|
|||
return nsGkAtoms::svgTextPathFrame;
|
||||
}
|
||||
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextPathFrame::GetX()
|
||||
void
|
||||
nsSVGTextPathFrame::GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY)
|
||||
{
|
||||
return nsnull;
|
||||
// 'x' and 'y' don't apply to 'textPath'
|
||||
aX->Clear();
|
||||
aY->Clear();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextPathFrame::GetY()
|
||||
void
|
||||
nsSVGTextPathFrame::GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy)
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextPathFrame::GetDx()
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGLengthList>
|
||||
nsSVGTextPathFrame::GetDy()
|
||||
{
|
||||
return nsnull;
|
||||
// 'dx' and 'dy' don't apply to 'textPath'
|
||||
aDx->Clear();
|
||||
aDy->Clear();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMSVGNumberList>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#define NSSVGTEXTPATHFRAME_H
|
||||
|
||||
#include "nsSVGTSpanFrame.h"
|
||||
#include "nsSVGLengthList.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsSVGNumberList.h"
|
||||
|
||||
typedef nsSVGTSpanFrame nsSVGTextPathFrameBase;
|
||||
|
@ -85,10 +85,8 @@ public:
|
|||
gfxFloat GetPathScale();
|
||||
protected:
|
||||
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetX();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetY();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetDx();
|
||||
virtual already_AddRefed<nsIDOMSVGLengthList> GetDy();
|
||||
virtual void GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY);
|
||||
virtual void GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy);
|
||||
virtual already_AddRefed<nsIDOMSVGNumberList> GetRotate();
|
||||
|
||||
private:
|
||||
|
|
|
@ -264,6 +264,7 @@ nsSVGUtils::GetFontSize(Element *aElement)
|
|||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nsnull, nsnull);
|
||||
if (!styleContext) {
|
||||
// ReportToConsole
|
||||
NS_WARNING("Couldn't get style context for content in GetFontStyle");
|
||||
return 1.0f;
|
||||
}
|
||||
|
@ -301,6 +302,7 @@ nsSVGUtils::GetFontXHeight(Element *aElement)
|
|||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nsnull, nsnull);
|
||||
if (!styleContext) {
|
||||
// ReportToConsole
|
||||
NS_WARNING("Couldn't get style context for content in GetFontStyle");
|
||||
return 1.0f;
|
||||
}
|
||||
|
@ -328,6 +330,7 @@ nsSVGUtils::GetFontXHeight(nsStyleContext *aStyleContext)
|
|||
getter_AddRefs(fontMetrics));
|
||||
|
||||
if (!fontMetrics) {
|
||||
// ReportToConsole
|
||||
NS_WARNING("no FontMetrics in GetFontXHeight()");
|
||||
return 1.0f;
|
||||
}
|
||||
|
|
|
@ -213,13 +213,21 @@ public:
|
|||
static mozilla::dom::Element *GetParentElement(nsIContent *aContent);
|
||||
|
||||
/*
|
||||
* Get a font-size (em) of an nsIContent
|
||||
* Get the number of CSS px (user units) per em (i.e. the em-height in user
|
||||
* units) for an nsIContent
|
||||
*
|
||||
* XXX document the conditions under which these may fail, and what they
|
||||
* return in those cases.
|
||||
*/
|
||||
static float GetFontSize(mozilla::dom::Element *aElement);
|
||||
static float GetFontSize(nsIFrame *aFrame);
|
||||
static float GetFontSize(nsStyleContext *aStyleContext);
|
||||
/*
|
||||
* Get an x-height of of an nsIContent
|
||||
* Get the number of CSS px (user units) per ex (i.e. the x-height in user
|
||||
* units) for an nsIContent
|
||||
*
|
||||
* XXX document the conditions under which these may fail, and what they
|
||||
* return in those cases.
|
||||
*/
|
||||
static float GetFontXHeight(mozilla::dom::Element *aElement);
|
||||
static float GetFontXHeight(nsIFrame *aFrame);
|
||||
|
|
Загрузка…
Ссылка в новой задаче