summaryrefslogtreecommitdiffstats
path: root/dom/svg/SVGTransformListParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/svg/SVGTransformListParser.cpp')
-rw-r--r--dom/svg/SVGTransformListParser.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/dom/svg/SVGTransformListParser.cpp b/dom/svg/SVGTransformListParser.cpp
new file mode 100644
index 000000000..635c96b11
--- /dev/null
+++ b/dom/svg/SVGTransformListParser.cpp
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ArrayUtils.h"
+
+#include "SVGTransformListParser.h"
+#include "SVGContentUtils.h"
+#include "nsSVGTransform.h"
+#include "nsGkAtoms.h"
+#include "nsIAtom.h"
+
+using namespace mozilla;
+
+//----------------------------------------------------------------------
+// private methods
+
+bool
+SVGTransformListParser::Parse()
+{
+ mTransforms.Clear();
+ return ParseTransforms();
+}
+
+bool
+SVGTransformListParser::ParseTransforms()
+{
+ if (!SkipWsp()) {
+ return true;
+ }
+
+ if (!ParseTransform()) {
+ return false;
+ }
+
+ while (SkipWsp()) {
+ // The SVG BNF allows multiple comma-wsp between transforms
+ while (*mIter == ',') {
+ ++mIter;
+ if (!SkipWsp()) {
+ return false;
+ }
+ }
+
+ if (!ParseTransform()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+SVGTransformListParser::ParseTransform()
+{
+ RangedPtr<const char16_t> start(mIter);
+ while (IsAlpha(*mIter)) {
+ ++mIter;
+ if (mIter == mEnd) {
+ return false;
+ }
+ }
+
+ if (start == mIter) {
+ // Didn't read anything
+ return false;
+ }
+
+ const nsAString& transform = Substring(start.get(), mIter.get());
+ nsIAtom* keyAtom = NS_GetStaticAtom(transform);
+
+ if (!keyAtom || !SkipWsp()) {
+ return false;
+ }
+
+ if (keyAtom == nsGkAtoms::translate) {
+ return ParseTranslate();
+ }
+ if (keyAtom == nsGkAtoms::scale) {
+ return ParseScale();
+ }
+ if (keyAtom == nsGkAtoms::rotate) {
+ return ParseRotate();
+ }
+ if (keyAtom == nsGkAtoms::skewX) {
+ return ParseSkewX();
+ }
+ if (keyAtom == nsGkAtoms::skewY) {
+ return ParseSkewY();
+ }
+ if (keyAtom == nsGkAtoms::matrix) {
+ return ParseMatrix();
+ }
+ return false;
+}
+
+bool
+SVGTransformListParser::ParseArguments(float* aResult,
+ uint32_t aMaxCount,
+ uint32_t* aParsedCount)
+{
+ if (*mIter != '(') {
+ return false;
+ }
+ ++mIter;
+
+ if (!SkipWsp()) {
+ return false;
+ }
+
+ if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[0])) {
+ return false;
+ }
+ *aParsedCount = 1;
+
+ while (SkipWsp()) {
+ if (*mIter == ')') {
+ ++mIter;
+ return true;
+ }
+ if (*aParsedCount == aMaxCount) {
+ return false;
+ }
+ SkipCommaWsp();
+ if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[(*aParsedCount)++])) {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+SVGTransformListParser::ParseTranslate()
+{
+ float t[2];
+ uint32_t count;
+
+ if (!ParseArguments(t, ArrayLength(t), &count)) {
+ return false;
+ }
+
+ switch (count) {
+ case 1:
+ t[1] = 0.f;
+ MOZ_FALLTHROUGH;
+ case 2:
+ {
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetTranslate(t[0], t[1]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+SVGTransformListParser::ParseScale()
+{
+ float s[2];
+ uint32_t count;
+
+ if (!ParseArguments(s, ArrayLength(s), &count)) {
+ return false;
+ }
+
+ switch (count) {
+ case 1:
+ s[1] = s[0];
+ MOZ_FALLTHROUGH;
+ case 2:
+ {
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetScale(s[0], s[1]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool
+SVGTransformListParser::ParseRotate()
+{
+ float r[3];
+ uint32_t count;
+
+ if (!ParseArguments(r, ArrayLength(r), &count)) {
+ return false;
+ }
+
+ switch (count) {
+ case 1:
+ r[1] = r[2] = 0.f;
+ MOZ_FALLTHROUGH;
+ case 3:
+ {
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetRotate(r[0], r[1], r[2]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+SVGTransformListParser::ParseSkewX()
+{
+ float skew;
+ uint32_t count;
+
+ if (!ParseArguments(&skew, 1, &count) || count != 1) {
+ return false;
+ }
+
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetSkewX(skew);
+
+ return true;
+}
+
+bool
+SVGTransformListParser::ParseSkewY()
+{
+ float skew;
+ uint32_t count;
+
+ if (!ParseArguments(&skew, 1, &count) || count != 1) {
+ return false;
+ }
+
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetSkewY(skew);
+
+ return true;
+}
+
+bool
+SVGTransformListParser::ParseMatrix()
+{
+ float m[6];
+ uint32_t count;
+
+ if (!ParseArguments(m, ArrayLength(m), &count) || count != 6) {
+ return false;
+ }
+
+ nsSVGTransform* transform = mTransforms.AppendElement(fallible);
+ if (!transform) {
+ return false;
+ }
+ transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5]));
+
+ return true;
+}