diff options
Diffstat (limited to 'layout/style/nsStyleTransformMatrix.h')
-rw-r--r-- | layout/style/nsStyleTransformMatrix.h | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/layout/style/nsStyleTransformMatrix.h b/layout/style/nsStyleTransformMatrix.h new file mode 100644 index 000000000..bde87c7ad --- /dev/null +++ b/layout/style/nsStyleTransformMatrix.h @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +/* + * A class representing three matrices that can be used for style transforms. + */ + +#ifndef nsStyleTransformMatrix_h_ +#define nsStyleTransformMatrix_h_ + +#include "mozilla/EnumeratedArray.h" +#include "nsCSSValue.h" + +#include <limits> + +class nsIFrame; +class nsStyleContext; +class nsPresContext; +struct gfxQuaternion; +struct nsRect; +namespace mozilla { +class RuleNodeCacheConditions; +} // namespace mozilla + +/** + * A helper to generate gfxMatrixes from css transform functions. + */ +namespace nsStyleTransformMatrix { + + // Function for applying perspective() transform function. We treat + // any value smaller than epsilon as perspective(infinity), which + // follows CSSWG's resolution on perspective(0). See bug 1316236. + inline void ApplyPerspectiveToMatrix(mozilla::gfx::Matrix4x4& aMatrix, + float aDepth) + { + if (aDepth >= std::numeric_limits<float>::epsilon()) { + aMatrix.Perspective(aDepth); + } + } + + /** + * This class provides on-demand access to the 'reference box' for CSS + * transforms (needed to resolve percentage values in 'transform', + * 'transform-origin', etc.): + * + * http://dev.w3.org/csswg/css-transforms/#reference-box + * + * This class helps us to avoid calculating the reference box unless and + * until it is actually needed. This is important for performance when + * transforms are applied to SVG elements since the reference box for SVG is + * much more expensive to calculate (than for elements with a CSS layout box + * where we can use the nsIFrame's cached mRect), much more common (than on + * HTML), and yet very rarely have percentage values that require the + * reference box to be resolved. We also don't want to cause SVG frames to + * cache lots of ObjectBoundingBoxProperty objects that aren't needed. + * + * If UNIFIED_CONTINUATIONS (experimental, and currently broke) is defined, + * we consider the reference box for non-SVG frames to be the smallest + * rectangle containing a frame and all of its continuations. For example, + * if there is a <span> element with several continuations split over + * several lines, this function will return the rectangle containing all of + * those continuations. (This behavior is not currently in a spec.) + */ + class MOZ_STACK_CLASS TransformReferenceBox final { + public: + typedef nscoord (TransformReferenceBox::*DimensionGetter)(); + + explicit TransformReferenceBox() + : mFrame(nullptr) + , mIsCached(false) + {} + + explicit TransformReferenceBox(const nsIFrame* aFrame) + : mFrame(aFrame) + , mIsCached(false) + { + MOZ_ASSERT(mFrame); + } + + explicit TransformReferenceBox(const nsIFrame* aFrame, + const nsSize& aFallbackDimensions) + { + mFrame = aFrame; + mIsCached = false; + if (!mFrame) { + Init(aFallbackDimensions); + } + } + + void Init(const nsIFrame* aFrame) { + MOZ_ASSERT(!mFrame && !mIsCached); + mFrame = aFrame; + } + + void Init(const nsSize& aDimensions); + + /** + * The offset of the reference box from the nsIFrame's TopLeft(). This + * is non-zero only in the case of SVG content. If we can successfully + * implement UNIFIED_CONTINUATIONS at some point in the future then it + * may also be non-zero for non-SVG content. + */ + nscoord X() { + EnsureDimensionsAreCached(); + return mX; + } + nscoord Y() { + EnsureDimensionsAreCached(); + return mY; + } + + /** + * The size of the reference box. + */ + nscoord Width() { + EnsureDimensionsAreCached(); + return mWidth; + } + nscoord Height() { + EnsureDimensionsAreCached(); + return mHeight; + } + + bool IsEmpty() { + return !mFrame; + } + + private: + // We don't really need to prevent copying, but since none of our consumers + // currently need to copy, preventing copying may allow us to catch some + // cases where we use pass-by-value instead of pass-by-reference. + TransformReferenceBox(const TransformReferenceBox&) = delete; + + void EnsureDimensionsAreCached(); + + const nsIFrame* mFrame; + nscoord mX, mY, mWidth, mHeight; + bool mIsCached; + }; + + /** + * Return the transform function, as an nsCSSKeyword, for the given + * nsCSSValue::Array from a transform list. + */ + nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData); + + void SetIdentityMatrix(nsCSSValue::Array* aMatrix); + + float ProcessTranslatePart(const nsCSSValue& aValue, + nsStyleContext* aContext, + nsPresContext* aPresContext, + mozilla::RuleNodeCacheConditions& aConditions, + TransformReferenceBox* aRefBox, + TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr); + + void + ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix, + const nsCSSValue::Array* aData, + nsStyleContext* aContext, + nsPresContext* aPresContext, + mozilla::RuleNodeCacheConditions& aConditions, + TransformReferenceBox& aBounds, + bool* aContains3dTransform); + + /** + * Given an nsCSSValueList containing -moz-transform functions, + * returns a matrix containing the value of those functions. + * + * @param aData The nsCSSValueList containing the transform functions + * @param aContext The style context, used for unit conversion. + * @param aPresContext The presentation context, used for unit conversion. + * @param aConditions Set to uncachable (by calling SetUncacheable()) if the + * result cannot be cached in the rule tree, otherwise untouched. + * @param aBounds The frame's bounding rectangle. + * @param aAppUnitsPerMatrixUnit The number of app units per device pixel. + * @param aContains3dTransform [out] Set to true if aList contains at least + * one 3d transform function (as defined in the CSS transforms + * specification), false otherwise. + * + * aContext and aPresContext may be null if all of the (non-percent) + * length values in aData are already known to have been converted to + * eCSSUnit_Pixel (as they are in an StyleAnimationValue) + */ + mozilla::gfx::Matrix4x4 ReadTransforms(const nsCSSValueList* aList, + nsStyleContext* aContext, + nsPresContext* aPresContext, + mozilla::RuleNodeCacheConditions& aConditions, + TransformReferenceBox& aBounds, + float aAppUnitsPerMatrixUnit, + bool* aContains3dTransform); + + // Shear type for decomposition. + enum class ShearType { + XYSHEAR, + XZSHEAR, + YZSHEAR, + Count + }; + using ShearArray = + mozilla::EnumeratedArray<ShearType, ShearType::Count, float>; + + /* + * Implements the 2d transform matrix decomposition algorithm. + */ + bool Decompose2DMatrix(const mozilla::gfx::Matrix& aMatrix, + mozilla::gfx::Point3D& aScale, + ShearArray& aShear, + gfxQuaternion& aRotate, + mozilla::gfx::Point3D& aTranslate); + /* + * Implements the 3d transform matrix decomposition algorithm. + */ + bool Decompose3DMatrix(const mozilla::gfx::Matrix4x4& aMatrix, + mozilla::gfx::Point3D& aScale, + ShearArray& aShear, + gfxQuaternion& aRotate, + mozilla::gfx::Point3D& aTranslate, + mozilla::gfx::Point4D& aPerspective); + + mozilla::gfx::Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray); + mozilla::gfx::Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray); +} // namespace nsStyleTransformMatrix + +#endif |