123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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/. */
- #include "nsSVGViewBox.h"
- #include "mozilla/Move.h"
- #include "nsCharSeparatedTokenizer.h"
- #include "nsSMILValue.h"
- #include "nsTextFormatter.h"
- #include "SVGContentUtils.h"
- #include "SVGViewBoxSMILType.h"
- #define NUM_VIEWBOX_COMPONENTS 4
- using namespace mozilla;
- /* Implementation of nsSVGViewBoxRect methods */
- bool
- nsSVGViewBoxRect::operator==(const nsSVGViewBoxRect& aOther) const
- {
- if (&aOther == this)
- return true;
- return (none && aOther.none) ||
- (!none && !aOther.none &&
- x == aOther.x &&
- y == aOther.y &&
- width == aOther.width &&
- height == aOther.height);
- }
- /* Cycle collection macros for nsSVGViewBox */
- NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(nsSVGViewBox::DOMBaseVal, mSVGElement)
- NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(nsSVGViewBox::DOMAnimVal, mSVGElement)
- NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMBaseVal)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMBaseVal)
- NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimVal)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimVal)
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMBaseVal>
- sBaseSVGViewBoxTearoffTable;
- static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMAnimVal>
- sAnimSVGViewBoxTearoffTable;
- nsSVGAttrTearoffTable<nsSVGViewBox, dom::SVGAnimatedRect>
- nsSVGViewBox::sSVGAnimatedRectTearoffTable;
- /* Implementation of nsSVGViewBox methods */
- void
- nsSVGViewBox::Init()
- {
- mHasBaseVal = false;
- // We shouldn't use mBaseVal for rendering (its usages should be guarded with
- // "mHasBaseVal" checks), but just in case we do by accident, this will
- // ensure that we treat it as "none" and ignore its numeric values:
- mBaseVal.none = true;
- mAnimVal = nullptr;
- }
- bool
- nsSVGViewBox::HasRect() const
- {
- // Check mAnimVal if we have one; otherwise, check mBaseVal if we have one;
- // otherwise, just return false (we clearly do not have a rect).
- const nsSVGViewBoxRect* rect = mAnimVal;
- if (!rect) {
- if (!mHasBaseVal) {
- // no anim val, no base val --> no viewbox rect
- return false;
- }
- rect = &mBaseVal;
- }
- return !rect->none && rect->width >= 0 && rect->height >= 0;
- }
- void
- nsSVGViewBox::SetAnimValue(const nsSVGViewBoxRect& aRect,
- nsSVGElement *aSVGElement)
- {
- if (!mAnimVal) {
- // it's okay if allocation fails - and no point in reporting that
- mAnimVal = new nsSVGViewBoxRect(aRect);
- } else {
- if (aRect == *mAnimVal) {
- return;
- }
- *mAnimVal = aRect;
- }
- aSVGElement->DidAnimateViewBox();
- }
- void
- nsSVGViewBox::SetBaseValue(const nsSVGViewBoxRect& aRect,
- nsSVGElement *aSVGElement)
- {
- if (!mHasBaseVal || mBaseVal == aRect) {
- // This method is used to set a single x, y, width
- // or height value. It can't create a base value
- // as the other components may be undefined. We record
- // the new value though, so as not to lose data.
- mBaseVal = aRect;
- return;
- }
- nsAttrValue emptyOrOldValue = aSVGElement->WillChangeViewBox();
- mBaseVal = aRect;
- mHasBaseVal = true;
- aSVGElement->DidChangeViewBox(emptyOrOldValue);
- if (mAnimVal) {
- aSVGElement->AnimationNeedsResample();
- }
- }
- static nsresult
- ToSVGViewBoxRect(const nsAString& aStr, nsSVGViewBoxRect *aViewBox)
- {
- if (aStr.EqualsLiteral("none")) {
- aViewBox->none = true;
- return NS_OK;
- }
- nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
- tokenizer(aStr, ',',
- nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
- float vals[NUM_VIEWBOX_COMPONENTS];
- uint32_t i;
- for (i = 0; i < NUM_VIEWBOX_COMPONENTS && tokenizer.hasMoreTokens(); ++i) {
- if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), vals[i])) {
- return NS_ERROR_DOM_SYNTAX_ERR;
- }
- }
- if (i != NUM_VIEWBOX_COMPONENTS || // Too few values.
- tokenizer.hasMoreTokens() || // Too many values.
- tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
- return NS_ERROR_DOM_SYNTAX_ERR;
- }
- aViewBox->x = vals[0];
- aViewBox->y = vals[1];
- aViewBox->width = vals[2];
- aViewBox->height = vals[3];
- aViewBox->none = false;
- return NS_OK;
- }
- nsresult
- nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
- nsSVGElement *aSVGElement,
- bool aDoSetAttr)
- {
- nsSVGViewBoxRect viewBox;
- nsresult rv = ToSVGViewBoxRect(aValue, &viewBox);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Comparison against mBaseVal is only valid if we currently have a base val.
- if (mHasBaseVal && viewBox == mBaseVal) {
- return NS_OK;
- }
- nsAttrValue emptyOrOldValue;
- if (aDoSetAttr) {
- emptyOrOldValue = aSVGElement->WillChangeViewBox();
- }
- mHasBaseVal = true;
- mBaseVal = viewBox;
- if (aDoSetAttr) {
- aSVGElement->DidChangeViewBox(emptyOrOldValue);
- }
- if (mAnimVal) {
- aSVGElement->AnimationNeedsResample();
- }
- return NS_OK;
- }
- void
- nsSVGViewBox::GetBaseValueString(nsAString& aValue) const
- {
- if (mBaseVal.none) {
- aValue.AssignLiteral("none");
- return;
- }
- char16_t buf[200];
- nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
- u"%g %g %g %g",
- (double)mBaseVal.x, (double)mBaseVal.y,
- (double)mBaseVal.width, (double)mBaseVal.height);
- aValue.Assign(buf);
- }
- already_AddRefed<dom::SVGAnimatedRect>
- nsSVGViewBox::ToSVGAnimatedRect(nsSVGElement* aSVGElement)
- {
- RefPtr<dom::SVGAnimatedRect> domAnimatedRect =
- sSVGAnimatedRectTearoffTable.GetTearoff(this);
- if (!domAnimatedRect) {
- domAnimatedRect = new dom::SVGAnimatedRect(this, aSVGElement);
- sSVGAnimatedRectTearoffTable.AddTearoff(this, domAnimatedRect);
- }
- return domAnimatedRect.forget();
- }
- already_AddRefed<dom::SVGIRect>
- nsSVGViewBox::ToDOMBaseVal(nsSVGElement *aSVGElement)
- {
- if (!mHasBaseVal || mBaseVal.none) {
- return nullptr;
- }
- RefPtr<DOMBaseVal> domBaseVal =
- sBaseSVGViewBoxTearoffTable.GetTearoff(this);
- if (!domBaseVal) {
- domBaseVal = new DOMBaseVal(this, aSVGElement);
- sBaseSVGViewBoxTearoffTable.AddTearoff(this, domBaseVal);
- }
- return domBaseVal.forget();
- }
- nsSVGViewBox::DOMBaseVal::~DOMBaseVal()
- {
- sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
- }
- already_AddRefed<dom::SVGIRect>
- nsSVGViewBox::ToDOMAnimVal(nsSVGElement *aSVGElement)
- {
- if ((mAnimVal && mAnimVal->none) ||
- (!mAnimVal && (!mHasBaseVal || mBaseVal.none))) {
- return nullptr;
- }
- RefPtr<DOMAnimVal> domAnimVal =
- sAnimSVGViewBoxTearoffTable.GetTearoff(this);
- if (!domAnimVal) {
- domAnimVal = new DOMAnimVal(this, aSVGElement);
- sAnimSVGViewBoxTearoffTable.AddTearoff(this, domAnimVal);
- }
- return domAnimVal.forget();
- }
- nsSVGViewBox::DOMAnimVal::~DOMAnimVal()
- {
- sAnimSVGViewBoxTearoffTable.RemoveTearoff(mVal);
- }
- void
- nsSVGViewBox::DOMBaseVal::SetX(float aX, ErrorResult& aRv)
- {
- nsSVGViewBoxRect rect = mVal->GetBaseValue();
- rect.x = aX;
- mVal->SetBaseValue(rect, mSVGElement);
- }
- void
- nsSVGViewBox::DOMBaseVal::SetY(float aY, ErrorResult& aRv)
- {
- nsSVGViewBoxRect rect = mVal->GetBaseValue();
- rect.y = aY;
- mVal->SetBaseValue(rect, mSVGElement);
- }
- void
- nsSVGViewBox::DOMBaseVal::SetWidth(float aWidth, ErrorResult& aRv)
- {
- nsSVGViewBoxRect rect = mVal->GetBaseValue();
- rect.width = aWidth;
- mVal->SetBaseValue(rect, mSVGElement);
- }
- void
- nsSVGViewBox::DOMBaseVal::SetHeight(float aHeight, ErrorResult& aRv)
- {
- nsSVGViewBoxRect rect = mVal->GetBaseValue();
- rect.height = aHeight;
- mVal->SetBaseValue(rect, mSVGElement);
- }
- nsISMILAttr*
- nsSVGViewBox::ToSMILAttr(nsSVGElement *aSVGElement)
- {
- return new SMILViewBox(this, aSVGElement);
- }
- nsresult
- nsSVGViewBox::SMILViewBox
- ::ValueFromString(const nsAString& aStr,
- const dom::SVGAnimationElement* /*aSrcElement*/,
- nsSMILValue& aValue,
- bool& aPreventCachingOfSandwich) const
- {
- nsSVGViewBoxRect viewBox;
- nsresult res = ToSVGViewBoxRect(aStr, &viewBox);
- if (NS_FAILED(res)) {
- return res;
- }
- nsSMILValue val(&SVGViewBoxSMILType::sSingleton);
- *static_cast<nsSVGViewBoxRect*>(val.mU.mPtr) = viewBox;
- aValue = Move(val);
- aPreventCachingOfSandwich = false;
-
- return NS_OK;
- }
- nsSMILValue
- nsSVGViewBox::SMILViewBox::GetBaseValue() const
- {
- nsSMILValue val(&SVGViewBoxSMILType::sSingleton);
- *static_cast<nsSVGViewBoxRect*>(val.mU.mPtr) = mVal->mBaseVal;
- return val;
- }
- void
- nsSVGViewBox::SMILViewBox::ClearAnimValue()
- {
- if (mVal->mAnimVal) {
- mVal->mAnimVal = nullptr;
- mSVGElement->DidAnimateViewBox();
- }
- }
- nsresult
- nsSVGViewBox::SMILViewBox::SetAnimValue(const nsSMILValue& aValue)
- {
- NS_ASSERTION(aValue.mType == &SVGViewBoxSMILType::sSingleton,
- "Unexpected type to assign animated value");
- if (aValue.mType == &SVGViewBoxSMILType::sSingleton) {
- nsSVGViewBoxRect &vb = *static_cast<nsSVGViewBoxRect*>(aValue.mU.mPtr);
- mVal->SetAnimValue(vb, mSVGElement);
- }
- return NS_OK;
- }
|