1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
/* -*- 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/. */
#ifndef DOM_SVG_SVGANIMATEDLENGTH_H_
#define DOM_SVG_SVGANIMATEDLENGTH_H_
#include "mozilla/Attributes.h"
#include "mozilla/SMILAttr.h"
#include "mozilla/SVGContentUtils.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/SVGElement.h"
#include "mozilla/dom/SVGLengthBinding.h"
#include "nsError.h"
struct GeckoFontMetrics;
class nsPresContext;
class nsFontMetrics;
class mozAutoDocUpdate;
class nsIFrame;
namespace mozilla {
class AutoChangeLengthNotifier;
class SMILValue;
namespace dom {
class DOMSVGAnimatedLength;
class DOMSVGLength;
class SVGAnimationElement;
class SVGViewportElement;
class UserSpaceMetrics {
public:
enum class Type : uint32_t { This, Root };
static GeckoFontMetrics DefaultFontMetrics();
static GeckoFontMetrics GetFontMetrics(const Element* aElement);
static WritingMode GetWritingMode(const Element* aElement);
static float GetZoom(const Element* aElement);
static CSSSize GetCSSViewportSizeFromContext(const nsPresContext* aContext);
virtual ~UserSpaceMetrics() = default;
virtual float GetEmLength(Type aType) const = 0;
virtual float GetZoom() const = 0;
virtual float GetRootZoom() const = 0;
float GetExLength(Type aType) const;
float GetChSize(Type aType) const;
float GetIcWidth(Type aType) const;
float GetCapHeight(Type aType) const;
virtual float GetAxisLength(uint8_t aCtxType) const = 0;
virtual CSSSize GetCSSViewportSize() const = 0;
virtual float GetLineHeight(Type aType) const = 0;
protected:
virtual GeckoFontMetrics GetFontMetricsForType(Type aType) const = 0;
virtual WritingMode GetWritingModeForType(Type aType) const = 0;
};
class UserSpaceMetricsWithSize : public UserSpaceMetrics {
public:
virtual gfx::Size GetSize() const = 0;
float GetAxisLength(uint8_t aCtxType) const override;
};
class SVGElementMetrics final : public UserSpaceMetrics {
public:
explicit SVGElementMetrics(const SVGElement* aSVGElement,
const SVGViewportElement* aCtx = nullptr);
float GetEmLength(Type aType) const override {
return SVGContentUtils::GetFontSize(GetElementForType(aType));
}
float GetAxisLength(uint8_t aCtxType) const override;
CSSSize GetCSSViewportSize() const override;
float GetLineHeight(Type aType) const override;
float GetZoom() const override;
float GetRootZoom() const override;
private:
bool EnsureCtx() const;
const Element* GetElementForType(Type aType) const;
GeckoFontMetrics GetFontMetricsForType(Type aType) const override;
WritingMode GetWritingModeForType(Type aType) const override;
const SVGElement* mSVGElement;
mutable const SVGViewportElement* mCtx;
};
class NonSVGFrameUserSpaceMetrics final : public UserSpaceMetricsWithSize {
public:
explicit NonSVGFrameUserSpaceMetrics(nsIFrame* aFrame);
float GetEmLength(Type aType) const override;
gfx::Size GetSize() const override;
CSSSize GetCSSViewportSize() const override;
float GetLineHeight(Type aType) const override;
float GetZoom() const override;
float GetRootZoom() const override;
private:
GeckoFontMetrics GetFontMetricsForType(Type aType) const override;
WritingMode GetWritingModeForType(Type aType) const override;
nsIFrame* mFrame;
};
} // namespace dom
class SVGAnimatedLength {
friend class AutoChangeLengthNotifier;
friend class dom::DOMSVGAnimatedLength;
friend class dom::DOMSVGLength;
using DOMSVGLength = dom::DOMSVGLength;
using SVGElement = dom::SVGElement;
using SVGViewportElement = dom::SVGViewportElement;
using UserSpaceMetrics = dom::UserSpaceMetrics;
public:
void Init(uint8_t aCtxType = SVGContentUtils::XY, uint8_t aAttrEnum = 0xff,
float aValue = 0,
uint8_t aUnitType = dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {
mAnimVal = mBaseVal = aValue;
mBaseUnitType = mAnimUnitType = aUnitType;
mAttrEnum = aAttrEnum;
mCtxType = aCtxType;
mIsAnimated = false;
mIsBaseSet = false;
}
SVGAnimatedLength& operator=(const SVGAnimatedLength& aLength) {
mBaseVal = aLength.mBaseVal;
mAnimVal = aLength.mAnimVal;
mBaseUnitType = aLength.mBaseUnitType;
mAnimUnitType = aLength.mAnimUnitType;
mIsAnimated = aLength.mIsAnimated;
mIsBaseSet = aLength.mIsBaseSet;
return *this;
}
nsresult SetBaseValueString(const nsAString& aValue, SVGElement* aSVGElement,
bool aDoSetAttr);
void GetBaseValueString(nsAString& aValue) const;
void GetAnimValueString(nsAString& aValue) const;
float GetBaseValue(const SVGElement* aSVGElement) const {
return mBaseVal * GetPixelsPerUnit(aSVGElement, mBaseUnitType);
}
float GetAnimValue(const SVGElement* aSVGElement) const {
return mAnimVal * GetPixelsPerUnit(aSVGElement, mAnimUnitType);
}
float GetAnimValueWithZoom(const SVGElement* aSVGElement) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aSVGElement, mAnimUnitType);
}
float GetAnimValueWithZoom(nsIFrame* aFrame) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aFrame, mAnimUnitType);
}
float GetAnimValueWithZoom(const SVGViewportElement* aCtx) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aCtx, mAnimUnitType);
}
float GetAnimValueWithZoom(const UserSpaceMetrics& aMetrics) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aMetrics, mAnimUnitType);
}
uint8_t GetCtxType() const { return mCtxType; }
uint8_t GetBaseUnitType() const { return mBaseUnitType; }
uint8_t GetAnimUnitType() const { return mAnimUnitType; }
bool IsPercentage() const {
return mAnimUnitType == dom::SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE;
}
float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
bool HasBaseVal() const { return mIsBaseSet; }
// Returns true if the animated value of this length has been explicitly
// set (either by animation, or by taking on the base value which has been
// explicitly set by markup or a DOM call), false otherwise.
// If this returns false, the animated value is still valid, that is,
// usable, and represents the default base value of the attribute.
bool IsExplicitlySet() const { return mIsAnimated || mIsBaseSet; }
bool IsAnimated() const { return mIsAnimated; }
already_AddRefed<dom::DOMSVGAnimatedLength> ToDOMAnimatedLength(
SVGElement* aSVGElement);
UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement);
private:
float mAnimVal;
float mBaseVal;
uint8_t mBaseUnitType;
uint8_t mAnimUnitType;
uint8_t mAttrEnum : 6; // element specified tracking for attribute
uint8_t mCtxType : 2; // X, Y or Unspecified
bool mIsAnimated : 1;
bool mIsBaseSet : 1;
// These APIs returns the number of user-unit pixels per unit of the
// given type, in a given context (frame/element/etc).
float GetPixelsPerUnit(const SVGElement* aSVGElement,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(nsIFrame* aFrame, uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const UserSpaceMetrics& aMetrics,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const SVGElement* aSVGElement,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const SVGViewportElement* aCtx,
uint8_t aUnitType) const;
// SetBaseValue and SetAnimValue set the value in user units. This may fail
// if unit conversion fails e.g. conversion to ex or em units where the
// font-size is 0.
// SetBaseValueInSpecifiedUnits and SetAnimValueInSpecifiedUnits do not
// perform unit conversion and are therefore infallible.
nsresult SetBaseValue(float aValue, SVGElement* aSVGElement, bool aDoSetAttr);
void SetBaseValueInSpecifiedUnits(float aValue, SVGElement* aSVGElement,
bool aDoSetAttr);
void SetAnimValue(float aValue, uint16_t aUnitType, SVGElement* aSVGElement);
void SetAnimValueInSpecifiedUnits(float aValue, SVGElement* aSVGElement);
void NewValueSpecifiedUnits(uint16_t aUnitType, float aValueInSpecifiedUnits,
SVGElement* aSVGElement);
void ConvertToSpecifiedUnits(uint16_t aUnitType, SVGElement* aSVGElement,
ErrorResult& aRv);
already_AddRefed<DOMSVGLength> ToDOMBaseVal(SVGElement* aSVGElement);
already_AddRefed<DOMSVGLength> ToDOMAnimVal(SVGElement* aSVGElement);
public:
struct SMILLength : public SMILAttr {
public:
SMILLength(SVGAnimatedLength* aVal, SVGElement* aSVGElement)
: mVal(aVal), mSVGElement(aSVGElement) {}
// These will stay alive because a SMILAttr only lives as long
// as the Compositing step, and DOM elements don't get a chance to
// die during that.
SVGAnimatedLength* mVal;
SVGElement* mSVGElement;
// SMILAttr methods
nsresult ValueFromString(const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
SMILValue& aValue,
bool& aPreventCachingOfSandwich) const override;
SMILValue GetBaseValue() const override;
void ClearAnimValue() override;
nsresult SetAnimValue(const SMILValue& aValue) override;
};
};
/**
* This class is used by the SMIL code when a length is to be stored in a
* SMILValue instance. Since SMILValue objects may be cached, it is necessary
* for us to hold a strong reference to our element so that it doesn't
* disappear out from under us if, say, the element is removed from the DOM
* tree.
*/
class SVGLengthAndInfo {
public:
SVGLengthAndInfo() = default;
explicit SVGLengthAndInfo(dom::SVGElement* aElement)
: mElement(do_GetWeakReference(aElement->AsNode())) {}
void SetInfo(dom::SVGElement* aElement) {
mElement = do_GetWeakReference(aElement->AsNode());
}
dom::SVGElement* Element() const {
nsCOMPtr<nsIContent> e = do_QueryReferent(mElement);
return static_cast<dom::SVGElement*>(e.get());
}
bool operator==(const SVGLengthAndInfo& rhs) const {
return mValue == rhs.mValue && mUnitType == rhs.mUnitType &&
mCtxType == rhs.mCtxType;
}
float Value() const { return mValue; }
uint8_t UnitType() const { return mUnitType; }
void CopyFrom(const SVGLengthAndInfo& rhs) {
mElement = rhs.mElement;
mValue = rhs.mValue;
mUnitType = rhs.mUnitType;
mCtxType = rhs.mCtxType;
}
float ConvertUnits(const SVGLengthAndInfo& aTo) const;
float ValueInPixels(const dom::UserSpaceMetrics& aMetrics) const;
void Add(const SVGLengthAndInfo& aValueToAdd, uint32_t aCount);
static void Interpolate(const SVGLengthAndInfo& aStart,
const SVGLengthAndInfo& aEnd, double aUnitDistance,
SVGLengthAndInfo& aResult);
/**
* Enables SVGAnimatedLength values to be copied into SVGLengthAndInfo
* objects. Note that callers should also call SetInfo() when using this
* method!
*/
void CopyBaseFrom(const SVGAnimatedLength& rhs) {
mValue = rhs.GetBaseValInSpecifiedUnits();
mUnitType = rhs.GetBaseUnitType();
mCtxType = rhs.GetCtxType();
}
void Set(float aValue, uint8_t aUnitType, uint8_t aCtxType) {
mValue = aValue;
mUnitType = aUnitType;
mCtxType = aCtxType;
}
private:
// We must keep a weak reference to our element because we may belong to a
// cached baseVal SMILValue. See the comments starting at:
// https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
// See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497
nsWeakPtr mElement;
float mValue = 0.0f;
uint8_t mUnitType = dom::SVGLength_Binding::SVG_LENGTHTYPE_NUMBER;
uint8_t mCtxType = SVGContentUtils::XY;
};
} // namespace mozilla
#endif // DOM_SVG_SVGANIMATEDLENGTH_H_
|