2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04: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/. */
|
2012-05-17 14:02:41 +04:00
|
|
|
|
|
|
|
#include "SVGFragmentIdentifier.h"
|
2013-08-14 10:56:21 +04:00
|
|
|
|
2013-01-10 03:02:45 +04:00
|
|
|
#include "mozilla/dom/SVGSVGElement.h"
|
2013-01-08 07:22:41 +04:00
|
|
|
#include "mozilla/dom/SVGViewElement.h"
|
2020-09-21 05:09:57 +03:00
|
|
|
#include "mozilla/SVGOuterSVGFrame.h"
|
2018-12-27 20:30:38 +03:00
|
|
|
#include "nsCharSeparatedTokenizer.h"
|
2018-12-27 02:46:38 +03:00
|
|
|
#include "SVGAnimatedTransformList.h"
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2015-12-03 01:36:23 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace dom;
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2013-05-05 11:20:25 +04:00
|
|
|
static bool IsMatchingParameter(const nsAString& aString,
|
|
|
|
const nsAString& aParameterName) {
|
2012-05-18 14:41:30 +04:00
|
|
|
// The first two tests ensure aString.Length() > aParameterName.Length()
|
|
|
|
// so it's then safe to do the third test
|
2012-05-17 14:02:41 +04:00
|
|
|
return StringBeginsWith(aString, aParameterName) && aString.Last() == ')' &&
|
2012-05-18 14:41:30 +04:00
|
|
|
aString.CharAt(aParameterName.Length()) == '(';
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
// Handles setting/clearing the root's mSVGView pointer.
|
|
|
|
class MOZ_RAII AutoSVGViewHandler {
|
|
|
|
public:
|
2020-07-30 17:22:38 +03:00
|
|
|
explicit AutoSVGViewHandler(SVGSVGElement* aRoot)
|
2015-12-14 03:58:01 +03:00
|
|
|
: mRoot(aRoot), mValid(false) {
|
|
|
|
mWasOverridden = mRoot->UseCurrentView();
|
|
|
|
mRoot->mSVGView = nullptr;
|
|
|
|
mRoot->mCurrentViewID = nullptr;
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
~AutoSVGViewHandler() {
|
|
|
|
if (!mWasOverridden && !mValid) {
|
|
|
|
// we weren't overridden before and we aren't
|
|
|
|
// overridden now so nothing has changed.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mValid) {
|
2020-02-25 23:03:26 +03:00
|
|
|
mRoot->mSVGView = std::move(mSVGView);
|
2015-12-14 03:58:01 +03:00
|
|
|
}
|
|
|
|
mRoot->InvalidateTransformNotifyFrame();
|
2020-09-21 05:09:57 +03:00
|
|
|
if (nsIFrame* f = mRoot->GetPrimaryFrame()) {
|
|
|
|
if (SVGOuterSVGFrame* osf = do_QueryFrame(f)) {
|
|
|
|
osf->MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
|
|
|
}
|
|
|
|
}
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
void CreateSVGView() {
|
|
|
|
MOZ_ASSERT(!mSVGView, "CreateSVGView should not be called multiple times");
|
2020-02-25 23:03:26 +03:00
|
|
|
mSVGView = MakeUnique<SVGView>();
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
bool ProcessAttr(const nsAString& aToken, const nsAString& aParams) {
|
|
|
|
MOZ_ASSERT(mSVGView, "CreateSVGView should have been called");
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
// SVGViewAttributes may occur in any order, but each type may only occur
|
|
|
|
// at most one time in a correctly formed SVGViewSpec.
|
|
|
|
// If we encounter any attribute more than once or get any syntax errors
|
|
|
|
// we're going to return false and cancel any changes.
|
2013-05-05 11:20:25 +04:00
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
if (IsMatchingParameter(aToken, u"viewBox"_ns)) {
|
|
|
|
if (mSVGView->mViewBox.IsExplicitlySet() ||
|
|
|
|
NS_FAILED(
|
|
|
|
mSVGView->mViewBox.SetBaseValueString(aParams, mRoot, false))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (IsMatchingParameter(aToken, u"preserveAspectRatio"_ns)) {
|
|
|
|
if (mSVGView->mPreserveAspectRatio.IsExplicitlySet() ||
|
|
|
|
NS_FAILED(mSVGView->mPreserveAspectRatio.SetBaseValueString(
|
|
|
|
aParams, mRoot, false))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (IsMatchingParameter(aToken, u"transform"_ns)) {
|
|
|
|
if (mSVGView->mTransforms) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-25 23:03:26 +03:00
|
|
|
mSVGView->mTransforms = MakeUnique<SVGAnimatedTransformList>();
|
2018-01-26 21:21:34 +03:00
|
|
|
if (NS_FAILED(
|
|
|
|
mSVGView->mTransforms->SetBaseValueString(aParams, mRoot))) {
|
2015-12-14 03:58:01 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (IsMatchingParameter(aToken, u"zoomAndPan"_ns)) {
|
|
|
|
if (mSVGView->mZoomAndPan.IsExplicitlySet()) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* valAtom = NS_GetStaticAtom(aParams);
|
2020-02-20 01:06:09 +03:00
|
|
|
if (!valAtom || !mSVGView->mZoomAndPan.SetBaseValueAtom(valAtom, mRoot)) {
|
2015-12-14 03:58:01 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2013-05-05 11:20:25 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
void SetValid() { mValid = true; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
SVGSVGElement* mRoot;
|
2020-02-25 23:03:26 +03:00
|
|
|
UniquePtr<SVGView> mSVGView;
|
2015-12-14 03:58:01 +03:00
|
|
|
bool mValid;
|
|
|
|
bool mWasOverridden;
|
|
|
|
};
|
2012-10-22 13:13:24 +04:00
|
|
|
|
2013-05-05 11:20:25 +04:00
|
|
|
bool SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
|
2015-12-14 03:58:01 +03:00
|
|
|
SVGSVGElement* aRoot) {
|
|
|
|
AutoSVGViewHandler viewHandler(aRoot);
|
|
|
|
|
2012-05-17 14:02:41 +04:00
|
|
|
if (!IsMatchingParameter(aViewSpec, u"svgView"_ns)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Each token is a SVGViewAttribute
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t bracketPos = aViewSpec.FindChar('(');
|
2012-08-25 21:02:34 +04:00
|
|
|
uint32_t lengthOfViewSpec = aViewSpec.Length() - bracketPos - 2;
|
2020-12-16 22:10:34 +03:00
|
|
|
nsCharSeparatedTokenizerTemplate<NS_TokenizerIgnoreNothing> tokenizer(
|
2012-08-25 21:02:34 +04:00
|
|
|
Substring(aViewSpec, bracketPos + 1, lengthOfViewSpec), ';');
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2012-05-31 14:39:12 +04:00
|
|
|
if (!tokenizer.hasMoreTokens()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-14 03:58:01 +03:00
|
|
|
viewHandler.CreateSVGView();
|
|
|
|
|
2012-05-31 14:39:12 +04:00
|
|
|
do {
|
2012-05-17 14:02:41 +04:00
|
|
|
nsAutoString token(tokenizer.nextToken());
|
|
|
|
|
|
|
|
bracketPos = token.FindChar('(');
|
|
|
|
if (bracketPos < 1 || token.Last() != ')') {
|
|
|
|
// invalid SVGViewAttribute syntax
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsAString& params =
|
|
|
|
Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
if (!viewHandler.ProcessAttr(token, params)) {
|
2012-05-17 14:02:41 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
} while (tokenizer.hasMoreTokens());
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
viewHandler.SetValid();
|
2012-05-17 14:02:41 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-05 11:20:25 +04:00
|
|
|
bool SVGFragmentIdentifier::ProcessFragmentIdentifier(
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* aDocument, const nsAString& aAnchorName) {
|
2015-03-03 14:08:59 +03:00
|
|
|
MOZ_ASSERT(aDocument->GetRootElement()->IsSVGElement(nsGkAtoms::svg),
|
2015-02-10 01:34:50 +03:00
|
|
|
"expecting an SVG root element");
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2023-01-24 01:15:15 +03:00
|
|
|
auto* rootElement = SVGSVGElement::FromNode(aDocument->GetRootElement());
|
2012-05-17 14:02:41 +04:00
|
|
|
|
2023-01-24 01:15:15 +03:00
|
|
|
const auto* viewElement =
|
|
|
|
SVGViewElement::FromNodeOrNull(aDocument->GetElementById(aAnchorName));
|
2012-05-17 14:02:41 +04:00
|
|
|
|
|
|
|
if (viewElement) {
|
2012-09-09 15:44:03 +04:00
|
|
|
if (!rootElement->mCurrentViewID) {
|
2020-02-25 23:03:26 +03:00
|
|
|
rootElement->mCurrentViewID = MakeUnique<nsString>();
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
2012-09-09 15:44:03 +04:00
|
|
|
*rootElement->mCurrentViewID = aAnchorName;
|
2015-12-14 03:58:01 +03:00
|
|
|
rootElement->mSVGView = nullptr;
|
2012-09-09 15:44:03 +04:00
|
|
|
rootElement->InvalidateTransformNotifyFrame();
|
2020-09-21 05:09:57 +03:00
|
|
|
if (nsIFrame* f = rootElement->GetPrimaryFrame()) {
|
|
|
|
if (SVGOuterSVGFrame* osf = do_QueryFrame(f)) {
|
|
|
|
osf->MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
|
|
|
}
|
|
|
|
}
|
2015-03-08 20:34:47 +03:00
|
|
|
// not an svgView()-style fragment identifier, return false so the caller
|
|
|
|
// continues processing to match any :target pseudo elements
|
|
|
|
return false;
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
|
|
|
|
2015-12-14 03:58:01 +03:00
|
|
|
return ProcessSVGViewSpec(aAnchorName, rootElement);
|
2012-05-17 14:02:41 +04:00
|
|
|
}
|
2015-12-03 01:36:23 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|