mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
283 lines
10 KiB
C++
283 lines
10 KiB
C++
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef UI_GFX_TRANSFORM_H_
|
|
#define UI_GFX_TRANSFORM_H_
|
|
|
|
#include <iosfwd>
|
|
#include <string>
|
|
|
|
#include "base/compiler_specific.h"
|
|
#include "third_party/skia/include/utils/SkMatrix44.h"
|
|
#include "ui/gfx/gfx_export.h"
|
|
#include "ui/gfx/vector2d_f.h"
|
|
|
|
namespace gfx {
|
|
|
|
class BoxF;
|
|
class RectF;
|
|
class Point;
|
|
class Point3F;
|
|
class Vector3dF;
|
|
|
|
// 4x4 transformation matrix. Transform is cheap and explicitly allows
|
|
// copy/assign.
|
|
class GFX_EXPORT Transform {
|
|
public:
|
|
|
|
enum SkipInitialization {
|
|
kSkipInitialization
|
|
};
|
|
|
|
Transform() : matrix_(SkMatrix44::kIdentity_Constructor) {}
|
|
|
|
// Skips initializing this matrix to avoid overhead, when we know it will be
|
|
// initialized before use.
|
|
Transform(SkipInitialization)
|
|
: matrix_(SkMatrix44::kUninitialized_Constructor) {}
|
|
Transform(const Transform& rhs) : matrix_(rhs.matrix_) {}
|
|
// Initialize with the concatenation of lhs * rhs.
|
|
Transform(const Transform& lhs, const Transform& rhs)
|
|
: matrix_(lhs.matrix_, rhs.matrix_) {}
|
|
// Constructs a transform from explicit 16 matrix elements. Elements
|
|
// should be given in row-major order.
|
|
Transform(SkMScalar col1row1,
|
|
SkMScalar col2row1,
|
|
SkMScalar col3row1,
|
|
SkMScalar col4row1,
|
|
SkMScalar col1row2,
|
|
SkMScalar col2row2,
|
|
SkMScalar col3row2,
|
|
SkMScalar col4row2,
|
|
SkMScalar col1row3,
|
|
SkMScalar col2row3,
|
|
SkMScalar col3row3,
|
|
SkMScalar col4row3,
|
|
SkMScalar col1row4,
|
|
SkMScalar col2row4,
|
|
SkMScalar col3row4,
|
|
SkMScalar col4row4);
|
|
// Constructs a transform from explicit 2d elements. All other matrix
|
|
// elements remain the same as the corresponding elements of an identity
|
|
// matrix.
|
|
Transform(SkMScalar col1row1,
|
|
SkMScalar col2row1,
|
|
SkMScalar col1row2,
|
|
SkMScalar col2row2,
|
|
SkMScalar x_translation,
|
|
SkMScalar y_translation);
|
|
~Transform() {}
|
|
|
|
bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
|
|
bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
|
|
|
|
// Resets this transform to the identity transform.
|
|
void MakeIdentity() { matrix_.setIdentity(); }
|
|
|
|
// Applies the current transformation on a 2d rotation and assigns the result
|
|
// to |this|.
|
|
void Rotate(double degrees) { RotateAboutZAxis(degrees); }
|
|
|
|
// Applies the current transformation on an axis-angle rotation and assigns
|
|
// the result to |this|.
|
|
void RotateAboutXAxis(double degrees);
|
|
void RotateAboutYAxis(double degrees);
|
|
void RotateAboutZAxis(double degrees);
|
|
void RotateAbout(const Vector3dF& axis, double degrees);
|
|
|
|
// Applies the current transformation on a scaling and assigns the result
|
|
// to |this|.
|
|
void Scale(SkMScalar x, SkMScalar y);
|
|
void Scale3d(SkMScalar x, SkMScalar y, SkMScalar z);
|
|
gfx::Vector2dF Scale2d() const {
|
|
return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
|
|
}
|
|
|
|
// Applies the current transformation on a translation and assigns the result
|
|
// to |this|.
|
|
void Translate(SkMScalar x, SkMScalar y);
|
|
void Translate3d(SkMScalar x, SkMScalar y, SkMScalar z);
|
|
|
|
// Applies the current transformation on a skew and assigns the result
|
|
// to |this|.
|
|
void SkewX(double angle_x);
|
|
void SkewY(double angle_y);
|
|
|
|
// Applies the current transformation on a perspective transform and assigns
|
|
// the result to |this|.
|
|
void ApplyPerspectiveDepth(SkMScalar depth);
|
|
|
|
// Applies a transformation on the current transformation
|
|
// (i.e. 'this = this * transform;').
|
|
void PreconcatTransform(const Transform& transform);
|
|
|
|
// Applies a transformation on the current transformation
|
|
// (i.e. 'this = transform * this;').
|
|
void ConcatTransform(const Transform& transform);
|
|
|
|
// Returns true if this is the identity matrix.
|
|
bool IsIdentity() const { return matrix_.isIdentity(); }
|
|
|
|
// Returns true if the matrix is either identity or pure translation.
|
|
bool IsIdentityOrTranslation() const { return matrix_.isTranslate(); }
|
|
|
|
// Returns true if the matrix is either the identity or a 2d translation.
|
|
bool IsIdentityOr2DTranslation() const {
|
|
return matrix_.isTranslate() && matrix_.get(2, 3) == 0;
|
|
}
|
|
|
|
// Returns true if the matrix is either identity or pure translation,
|
|
// allowing for an amount of inaccuracy as specified by the parameter.
|
|
bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance) const;
|
|
|
|
// Returns true if the matrix is either a positive scale and/or a translation.
|
|
bool IsPositiveScaleOrTranslation() const {
|
|
if (!IsScaleOrTranslation())
|
|
return false;
|
|
return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 &&
|
|
matrix_.get(2, 2) > 0.0;
|
|
}
|
|
|
|
// Returns true if the matrix is either identity or pure, non-fractional
|
|
// translation.
|
|
bool IsIdentityOrIntegerTranslation() const;
|
|
|
|
// Returns true if the matrix had only scaling components.
|
|
bool IsScale2d() const {
|
|
return !(matrix_.getType() & ~SkMatrix44::kScale_Mask);
|
|
}
|
|
|
|
// Returns true if the matrix is has only scaling and translation components.
|
|
bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
|
|
|
|
// Returns true if axis-aligned 2d rects will remain axis-aligned after being
|
|
// transformed by this matrix.
|
|
bool Preserves2dAxisAlignment() const;
|
|
|
|
// Returns true if the matrix has any perspective component that would
|
|
// change the w-component of a homogeneous point.
|
|
bool HasPerspective() const { return matrix_.hasPerspective(); }
|
|
|
|
// Returns true if this transform is non-singular.
|
|
bool IsInvertible() const { return matrix_.invert(NULL); }
|
|
|
|
// Returns true if a layer with a forward-facing normal of (0, 0, 1) would
|
|
// have its back side facing frontwards after applying the transform.
|
|
bool IsBackFaceVisible() const;
|
|
|
|
// Inverts the transform which is passed in. Returns true if successful.
|
|
bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
|
|
|
|
// Transposes this transform in place.
|
|
void Transpose();
|
|
|
|
// Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
|
|
// operation is not quite the same as an orthographic projection and is
|
|
// technically not a linear operation.
|
|
//
|
|
// One useful interpretation of doing this operation:
|
|
// - For x and y values, the new transform behaves effectively like an
|
|
// orthographic projection was added to the matrix sequence.
|
|
// - For z values, the new transform overrides any effect that the transform
|
|
// had on z, and instead it preserves the z value for any points that are
|
|
// transformed.
|
|
// - Because of linearity of transforms, this flattened transform also
|
|
// preserves the effect that any subsequent (multiplied from the right)
|
|
// transforms would have on z values.
|
|
//
|
|
void FlattenTo2d();
|
|
|
|
// Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
|
|
bool IsFlat() const;
|
|
|
|
// Returns the x and y translation components of the matrix.
|
|
Vector2dF To2dTranslation() const;
|
|
|
|
// Applies the transformation to the point.
|
|
void TransformPoint(Point3F* point) const;
|
|
|
|
// Applies the transformation to the point.
|
|
void TransformPoint(Point* point) const;
|
|
|
|
// Applies the reverse transformation on the point. Returns true if the
|
|
// transformation can be inverted.
|
|
bool TransformPointReverse(Point3F* point) const;
|
|
|
|
// Applies the reverse transformation on the point. Returns true if the
|
|
// transformation can be inverted. Rounds the result to the nearest point.
|
|
bool TransformPointReverse(Point* point) const;
|
|
|
|
// Applies transformation on the given rect. After the function completes,
|
|
// |rect| will be the smallest axis aligned bounding rect containing the
|
|
// transformed rect.
|
|
void TransformRect(RectF* rect) const;
|
|
|
|
// Applies the reverse transformation on the given rect. After the function
|
|
// completes, |rect| will be the smallest axis aligned bounding rect
|
|
// containing the transformed rect. Returns false if the matrix cannot be
|
|
// inverted.
|
|
bool TransformRectReverse(RectF* rect) const;
|
|
|
|
// Applies transformation on the given box. After the function completes,
|
|
// |box| will be the smallest axis aligned bounding box containing the
|
|
// transformed box.
|
|
void TransformBox(BoxF* box) const;
|
|
|
|
// Applies the reverse transformation on the given box. After the function
|
|
// completes, |box| will be the smallest axis aligned bounding box
|
|
// containing the transformed box. Returns false if the matrix cannot be
|
|
// inverted.
|
|
bool TransformBoxReverse(BoxF* box) const;
|
|
|
|
// Decomposes |this| and |from|, interpolates the decomposed values, and
|
|
// sets |this| to the reconstituted result. Returns false if either matrix
|
|
// can't be decomposed. Uses routines described in this spec:
|
|
// http://www.w3.org/TR/css3-3d-transforms/.
|
|
//
|
|
// Note: this call is expensive since we need to decompose the transform. If
|
|
// you're going to be calling this rapidly (e.g., in an animation) you should
|
|
// decompose once using gfx::DecomposeTransforms and reuse your
|
|
// DecomposedTransform.
|
|
bool Blend(const Transform& from, double progress);
|
|
|
|
void RoundTranslationComponents();
|
|
|
|
// Returns |this| * |other|.
|
|
Transform operator*(const Transform& other) const {
|
|
return Transform(*this, other);
|
|
}
|
|
|
|
// Sets |this| = |this| * |other|
|
|
Transform& operator*=(const Transform& other) {
|
|
PreconcatTransform(other);
|
|
return *this;
|
|
}
|
|
|
|
// Returns the underlying matrix.
|
|
const SkMatrix44& matrix() const { return matrix_; }
|
|
SkMatrix44& matrix() { return matrix_; }
|
|
|
|
std::string ToString() const;
|
|
|
|
private:
|
|
void TransformPointInternal(const SkMatrix44& xform,
|
|
Point* point) const;
|
|
|
|
void TransformPointInternal(const SkMatrix44& xform,
|
|
Point3F* point) const;
|
|
|
|
SkMatrix44 matrix_;
|
|
|
|
// copy/assign are allowed.
|
|
};
|
|
|
|
// This is declared here for use in gtest-based unit tests but is defined in
|
|
// the gfx_test_support target. Depend on that to use this in your unit test.
|
|
// This should not be used in production code - call ToString() instead.
|
|
void PrintTo(const Transform& transform, ::std::ostream* os);
|
|
|
|
} // namespace gfx
|
|
|
|
#endif // UI_GFX_TRANSFORM_H_
|