2011-09-25 14:04:27 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
#include "DOMSVGTransform.h"
|
|
|
|
#include "DOMSVGMatrix.h"
|
|
|
|
#include "SVGAnimatedTransformList.h"
|
2012-07-27 07:03:27 -07:00
|
|
|
#include "nsError.h"
|
2011-09-25 14:04:27 -07:00
|
|
|
#include <math.h>
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsISupports methods:
|
|
|
|
|
|
|
|
// 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(DOMSVGTransform)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGTransform)
|
|
|
|
// We may not belong to a list, so we must null check tmp->mList.
|
|
|
|
if (tmp->mList) {
|
2012-07-30 07:20:58 -07:00
|
|
|
tmp->mList->mItems[tmp->mListIndex] = nullptr;
|
2011-09-25 14:04:27 -07:00
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGTransform)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGTransform)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGTransform)
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
DOMCI_DATA(SVGTransform, mozilla::DOMSVGTransform)
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTransform)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(mozilla::DOMSVGTransform)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGTransform)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMSVGTransform)
|
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGTransform)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Ctors:
|
|
|
|
|
|
|
|
DOMSVGTransform::DOMSVGTransform(DOMSVGTransformList *aList,
|
|
|
|
PRUint32 aListIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIsAnimValItem)
|
2011-09-25 14:04:27 -07:00
|
|
|
: mList(aList)
|
|
|
|
, mListIndex(aListIndex)
|
|
|
|
, mIsAnimValItem(aIsAnimValItem)
|
2012-07-30 07:20:58 -07:00
|
|
|
, mTransform(nullptr)
|
|
|
|
, mMatrixTearoff(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
// These shifts are in sync with the members in the header.
|
|
|
|
NS_ABORT_IF_FALSE(aList &&
|
|
|
|
aListIndex <= MaxListIndex() &&
|
|
|
|
aIsAnimValItem < (1 << 1), "bad arg");
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
|
|
|
|
}
|
|
|
|
|
|
|
|
DOMSVGTransform::DOMSVGTransform()
|
2012-07-30 07:20:58 -07:00
|
|
|
: mList(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mListIndex(0)
|
2011-10-17 07:59:28 -07:00
|
|
|
, mIsAnimValItem(false)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mTransform(new SVGTransform()) // Default ctor for objects not in a list
|
|
|
|
// initialises to matrix type with identity
|
|
|
|
// matrix
|
2012-07-30 07:20:58 -07:00
|
|
|
, mMatrixTearoff(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
DOMSVGTransform::DOMSVGTransform(const gfxMatrix &aMatrix)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mList(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mListIndex(0)
|
2011-10-17 07:59:28 -07:00
|
|
|
, mIsAnimValItem(false)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mTransform(new SVGTransform(aMatrix))
|
2012-07-30 07:20:58 -07:00
|
|
|
, mMatrixTearoff(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
DOMSVGTransform::DOMSVGTransform(const SVGTransform &aTransform)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mList(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mListIndex(0)
|
2011-10-17 07:59:28 -07:00
|
|
|
, mIsAnimValItem(false)
|
2011-09-25 14:04:27 -07:00
|
|
|
, mTransform(new SVGTransform(aTransform))
|
2012-07-30 07:20:58 -07:00
|
|
|
, mMatrixTearoff(nullptr)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIDOMSVGTransform methods:
|
|
|
|
|
|
|
|
/* readonly attribute unsigned short type; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::GetType(PRUint16 *aType)
|
|
|
|
{
|
|
|
|
*aType = Transform().Type();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute nsIDOMSVGMatrix matrix; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::GetMatrix(nsIDOMSVGMatrix * *aMatrix)
|
|
|
|
{
|
|
|
|
if (!mMatrixTearoff) {
|
|
|
|
mMatrixTearoff = new DOMSVGMatrix(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aMatrix = mMatrixTearoff);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute float angle; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::GetAngle(float *aAngle)
|
|
|
|
{
|
|
|
|
*aAngle = Transform().Angle();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setMatrix (in nsIDOMSVGMatrix matrix); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetMatrix(nsIDOMSVGMatrix *matrix)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem)
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
|
|
|
|
nsCOMPtr<DOMSVGMatrix> domMatrix = do_QueryInterface(matrix);
|
|
|
|
if (!domMatrix)
|
|
|
|
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
SetMatrix(domMatrix->Matrix());
|
2011-09-25 14:04:27 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setTranslate (in float tx, in float ty); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetTranslate(float tx, float ty)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem) {
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE &&
|
|
|
|
Matrix().x0 == tx && Matrix().y0 == ty) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
Transform().SetTranslate(tx, ty);
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setScale (in float sx, in float sy); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetScale(float sx, float sy)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem) {
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
NS_ENSURE_FINITE2(sx, sy, NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SCALE &&
|
|
|
|
Matrix().xx == sx && Matrix().yy == sy) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
Transform().SetScale(sx, sy);
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setRotate (in float angle, in float cx, in float cy); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetRotate(float angle, float cx, float cy)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem) {
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
NS_ENSURE_FINITE3(angle, cx, cy, NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE) {
|
|
|
|
float currentCx, currentCy;
|
|
|
|
Transform().GetRotationOrigin(currentCx, currentCy);
|
|
|
|
if (Transform().Angle() == angle && currentCx == cx && currentCy == cy) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
Transform().SetRotate(angle, cx, cy);
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setSkewX (in float angle); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetSkewX(float angle)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem) {
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX &&
|
|
|
|
Transform().Angle() == angle) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
nsresult rv = Transform().SetSkewX(angle);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void setSkewY (in float angle); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
DOMSVGTransform::SetSkewY(float angle)
|
|
|
|
{
|
|
|
|
if (mIsAnimValItem) {
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-02-15 15:40:46 -08:00
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY &&
|
|
|
|
Transform().Angle() == angle) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
nsresult rv = Transform().SetSkewY(angle);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// List management methods:
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMSVGTransform::InsertingIntoList(DOMSVGTransformList *aList,
|
|
|
|
PRUint32 aListIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIsAnimValItem)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that is already in a list");
|
|
|
|
|
|
|
|
mList = aList;
|
|
|
|
mListIndex = aListIndex;
|
|
|
|
mIsAnimValItem = aIsAnimValItem;
|
2012-07-30 07:20:58 -07:00
|
|
|
mTransform = nullptr;
|
2011-09-25 14:04:27 -07:00
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGLength!");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMSVGTransform::RemovingFromList()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!mTransform,
|
|
|
|
"Item in list also has another non-list value associated with it");
|
|
|
|
|
|
|
|
mTransform = new SVGTransform(InternalItem());
|
2012-07-30 07:20:58 -07:00
|
|
|
mList = nullptr;
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsAnimValItem = false;
|
2011-09-25 14:04:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
SVGTransform&
|
|
|
|
DOMSVGTransform::InternalItem()
|
|
|
|
{
|
|
|
|
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
|
|
|
|
return mIsAnimValItem && alist->mAnimVal ?
|
|
|
|
(*alist->mAnimVal)[mListIndex] :
|
|
|
|
alist->mBaseVal[mListIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
const SVGTransform&
|
|
|
|
DOMSVGTransform::InternalItem() const
|
|
|
|
{
|
|
|
|
return const_cast<DOMSVGTransform *>(this)->InternalItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2011-09-25 14:04:27 -07:00
|
|
|
DOMSVGTransform::IndexIsValid()
|
|
|
|
{
|
|
|
|
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
|
|
|
|
return (mIsAnimValItem &&
|
|
|
|
mListIndex < alist->GetAnimValue().Length()) ||
|
|
|
|
(!mIsAnimValItem &&
|
|
|
|
mListIndex < alist->GetBaseValue().Length());
|
|
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Interface for DOMSVGMatrix's use
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMSVGTransform::SetMatrix(const gfxMatrix& aMatrix)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!mIsAnimValItem,
|
|
|
|
"Attempting to modify read-only transform");
|
2012-02-15 15:40:46 -08:00
|
|
|
|
|
|
|
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX &&
|
|
|
|
SVGTransform::MatricesEqual(Matrix(), aMatrix)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
|
2011-09-25 14:04:27 -07:00
|
|
|
Transform().SetMatrix(aMatrix);
|
2012-02-15 15:40:46 -08:00
|
|
|
NotifyElementDidChange(emptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMSVGTransform::ClearMatrixTearoff(DOMSVGMatrix* aMatrix)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mMatrixTearoff == aMatrix,
|
|
|
|
"Unexpected matrix pointer to be cleared");
|
2012-07-30 07:20:58 -07:00
|
|
|
mMatrixTearoff = nullptr;
|
2011-09-25 14:04:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation helpers
|
|
|
|
|
|
|
|
void
|
2012-02-15 15:40:46 -08:00
|
|
|
DOMSVGTransform::NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue)
|
2011-09-25 14:04:27 -07:00
|
|
|
{
|
|
|
|
if (HasOwner()) {
|
2012-02-15 15:40:46 -08:00
|
|
|
Element()->DidChangeTransformList(aEmptyOrOldValue);
|
2011-09-25 14:04:27 -07:00
|
|
|
if (mList->mAList->IsAnimating()) {
|
|
|
|
Element()->AnimationNeedsResample();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|