interpolated_transform.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gfx/interpolated_transform.h"
  5. #include <cmath>
  6. #include "base/check.h"
  7. #include "base/numerics/safe_conversions.h"
  8. #include "ui/gfx/animation/tween.h"
  9. namespace {
  10. static const double EPSILON = 1e-6;
  11. bool IsMultipleOfNinetyDegrees(double degrees) {
  12. double remainder = fabs(fmod(degrees, 90.0));
  13. return remainder < EPSILON || 90.0 - remainder < EPSILON;
  14. }
  15. // Returns false if |degrees| is not a multiple of ninety degrees or if
  16. // |rotation| is NULL. It does not affect |rotation| in this case. Otherwise
  17. // *rotation is set to be the appropriate sanitized rotation matrix. That is,
  18. // the rotation matrix corresponding to |degrees| which has entries that are all
  19. // either 0, 1 or -1.
  20. bool MassageRotationIfMultipleOfNinetyDegrees(gfx::Transform* rotation,
  21. float degrees) {
  22. if (!IsMultipleOfNinetyDegrees(degrees) || !rotation)
  23. return false;
  24. gfx::Transform transform;
  25. float degrees_by_ninety = degrees / 90.0f;
  26. int n = base::ClampRound(degrees_by_ninety);
  27. n %= 4;
  28. if (n < 0)
  29. n += 4;
  30. // n should now be in the range [0, 3]
  31. // clang-format off
  32. if (n == 1) {
  33. transform.matrix().setRotateAboutZAxisSinCos(1, 0);
  34. } else if (n == 2) {
  35. transform.matrix().setRotateAboutZAxisSinCos(0, -1);
  36. } else if (n == 3) {
  37. transform.matrix().setRotateAboutZAxisSinCos(-1, 0);
  38. }
  39. // clang-format on
  40. *rotation = transform;
  41. return true;
  42. }
  43. } // namespace
  44. namespace ui {
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // InterpolatedTransform
  47. //
  48. InterpolatedTransform::InterpolatedTransform()
  49. : start_time_(0.0f),
  50. end_time_(1.0f),
  51. reversed_(false) {
  52. }
  53. InterpolatedTransform::InterpolatedTransform(float start_time,
  54. float end_time)
  55. : start_time_(start_time),
  56. end_time_(end_time),
  57. reversed_(false) {
  58. }
  59. InterpolatedTransform::~InterpolatedTransform() {}
  60. gfx::Transform InterpolatedTransform::Interpolate(float t) const {
  61. if (reversed_)
  62. t = 1.0f - t;
  63. gfx::Transform result = InterpolateButDoNotCompose(t);
  64. if (child_.get()) {
  65. result.ConcatTransform(child_->Interpolate(t));
  66. }
  67. return result;
  68. }
  69. void InterpolatedTransform::SetChild(
  70. std::unique_ptr<InterpolatedTransform> child) {
  71. child_ = std::move(child);
  72. }
  73. inline float InterpolatedTransform::ValueBetween(float time,
  74. float start_value,
  75. float end_value) const {
  76. // can't handle NaN
  77. DCHECK(time == time && start_time_ == start_time_ && end_time_ == end_time_);
  78. if (time != time || start_time_ != start_time_ || end_time_ != end_time_)
  79. return start_value;
  80. // Ok if equal -- we'll get a step function. Note: if end_time_ ==
  81. // start_time_ == x, then if none of the numbers are NaN, then it
  82. // must be true that time < x or time >= x, so we will return early
  83. // due to one of the following if statements.
  84. DCHECK(end_time_ >= start_time_);
  85. if (time < start_time_)
  86. return start_value;
  87. if (time >= end_time_)
  88. return end_value;
  89. float t = (time - start_time_) / (end_time_ - start_time_);
  90. return static_cast<float>(
  91. gfx::Tween::DoubleValueBetween(t, start_value, end_value));
  92. }
  93. ///////////////////////////////////////////////////////////////////////////////
  94. // InterpolatedRotation
  95. //
  96. InterpolatedRotation::InterpolatedRotation(float start_degrees,
  97. float end_degrees)
  98. : InterpolatedTransform(),
  99. start_degrees_(start_degrees),
  100. end_degrees_(end_degrees) {
  101. }
  102. InterpolatedRotation::InterpolatedRotation(float start_degrees,
  103. float end_degrees,
  104. float start_time,
  105. float end_time)
  106. : InterpolatedTransform(start_time, end_time),
  107. start_degrees_(start_degrees),
  108. end_degrees_(end_degrees) {
  109. }
  110. InterpolatedRotation::~InterpolatedRotation() {}
  111. gfx::Transform InterpolatedRotation::InterpolateButDoNotCompose(float t) const {
  112. gfx::Transform result;
  113. float interpolated_degrees = ValueBetween(t, start_degrees_, end_degrees_);
  114. result.Rotate(interpolated_degrees);
  115. if (t == 0.0f || t == 1.0f)
  116. MassageRotationIfMultipleOfNinetyDegrees(&result, interpolated_degrees);
  117. return result;
  118. }
  119. ///////////////////////////////////////////////////////////////////////////////
  120. // InterpolatedAxisAngleRotation
  121. //
  122. InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
  123. const gfx::Vector3dF& axis,
  124. float start_degrees,
  125. float end_degrees)
  126. : InterpolatedTransform(),
  127. axis_(axis),
  128. start_degrees_(start_degrees),
  129. end_degrees_(end_degrees) {
  130. }
  131. InterpolatedAxisAngleRotation::InterpolatedAxisAngleRotation(
  132. const gfx::Vector3dF& axis,
  133. float start_degrees,
  134. float end_degrees,
  135. float start_time,
  136. float end_time)
  137. : InterpolatedTransform(start_time, end_time),
  138. axis_(axis),
  139. start_degrees_(start_degrees),
  140. end_degrees_(end_degrees) {
  141. }
  142. InterpolatedAxisAngleRotation::~InterpolatedAxisAngleRotation() {}
  143. gfx::Transform
  144. InterpolatedAxisAngleRotation::InterpolateButDoNotCompose(float t) const {
  145. gfx::Transform result;
  146. result.RotateAbout(axis_, ValueBetween(t, start_degrees_, end_degrees_));
  147. return result;
  148. }
  149. ///////////////////////////////////////////////////////////////////////////////
  150. // InterpolatedScale
  151. //
  152. InterpolatedScale::InterpolatedScale(float start_scale, float end_scale)
  153. : InterpolatedTransform(),
  154. start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
  155. end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
  156. }
  157. InterpolatedScale::InterpolatedScale(float start_scale, float end_scale,
  158. float start_time, float end_time)
  159. : InterpolatedTransform(start_time, end_time),
  160. start_scale_(gfx::Point3F(start_scale, start_scale, start_scale)),
  161. end_scale_(gfx::Point3F(end_scale, end_scale, end_scale)) {
  162. }
  163. InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
  164. const gfx::Point3F& end_scale)
  165. : InterpolatedTransform(),
  166. start_scale_(start_scale),
  167. end_scale_(end_scale) {
  168. }
  169. InterpolatedScale::InterpolatedScale(const gfx::Point3F& start_scale,
  170. const gfx::Point3F& end_scale,
  171. float start_time,
  172. float end_time)
  173. : InterpolatedTransform(start_time, end_time),
  174. start_scale_(start_scale),
  175. end_scale_(end_scale) {
  176. }
  177. InterpolatedScale::~InterpolatedScale() {}
  178. gfx::Transform InterpolatedScale::InterpolateButDoNotCompose(float t) const {
  179. gfx::Transform result;
  180. float scale_x = ValueBetween(t, start_scale_.x(), end_scale_.x());
  181. float scale_y = ValueBetween(t, start_scale_.y(), end_scale_.y());
  182. float scale_z = ValueBetween(t, start_scale_.z(), end_scale_.z());
  183. result.Scale3d(scale_x, scale_y, scale_z);
  184. return result;
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. // InterpolatedTranslation
  188. //
  189. InterpolatedTranslation::InterpolatedTranslation(const gfx::PointF& start_pos,
  190. const gfx::PointF& end_pos)
  191. : InterpolatedTransform(), start_pos_(start_pos), end_pos_(end_pos) {}
  192. InterpolatedTranslation::InterpolatedTranslation(const gfx::PointF& start_pos,
  193. const gfx::PointF& end_pos,
  194. float start_time,
  195. float end_time)
  196. : InterpolatedTransform(start_time, end_time),
  197. start_pos_(start_pos),
  198. end_pos_(end_pos) {}
  199. InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
  200. const gfx::Point3F& end_pos)
  201. : InterpolatedTransform(), start_pos_(start_pos), end_pos_(end_pos) {
  202. }
  203. InterpolatedTranslation::InterpolatedTranslation(const gfx::Point3F& start_pos,
  204. const gfx::Point3F& end_pos,
  205. float start_time,
  206. float end_time)
  207. : InterpolatedTransform(start_time, end_time),
  208. start_pos_(start_pos),
  209. end_pos_(end_pos) {
  210. }
  211. InterpolatedTranslation::~InterpolatedTranslation() {}
  212. gfx::Transform
  213. InterpolatedTranslation::InterpolateButDoNotCompose(float t) const {
  214. gfx::Transform result;
  215. result.Translate3d(ValueBetween(t, start_pos_.x(), end_pos_.x()),
  216. ValueBetween(t, start_pos_.y(), end_pos_.y()),
  217. ValueBetween(t, start_pos_.z(), end_pos_.z()));
  218. return result;
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. // InterpolatedConstantTransform
  222. //
  223. InterpolatedConstantTransform::InterpolatedConstantTransform(
  224. const gfx::Transform& transform)
  225. : InterpolatedTransform(),
  226. transform_(transform) {
  227. }
  228. gfx::Transform
  229. InterpolatedConstantTransform::InterpolateButDoNotCompose(float t) const {
  230. return transform_;
  231. }
  232. InterpolatedConstantTransform::~InterpolatedConstantTransform() {}
  233. ///////////////////////////////////////////////////////////////////////////////
  234. // InterpolatedTransformAboutPivot
  235. //
  236. InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
  237. const gfx::Point& pivot,
  238. std::unique_ptr<InterpolatedTransform> transform)
  239. : InterpolatedTransform() {
  240. Init(pivot, std::move(transform));
  241. }
  242. InterpolatedTransformAboutPivot::InterpolatedTransformAboutPivot(
  243. const gfx::Point& pivot,
  244. std::unique_ptr<InterpolatedTransform> transform,
  245. float start_time,
  246. float end_time)
  247. : InterpolatedTransform() {
  248. Init(pivot, std::move(transform));
  249. }
  250. InterpolatedTransformAboutPivot::~InterpolatedTransformAboutPivot() {}
  251. gfx::Transform
  252. InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const {
  253. if (transform_.get()) {
  254. return transform_->Interpolate(t);
  255. }
  256. return gfx::Transform();
  257. }
  258. void InterpolatedTransformAboutPivot::Init(
  259. const gfx::Point& pivot,
  260. std::unique_ptr<InterpolatedTransform> xform) {
  261. gfx::Transform to_pivot;
  262. gfx::Transform from_pivot;
  263. to_pivot.Translate(SkIntToScalar(-pivot.x()), SkIntToScalar(-pivot.y()));
  264. from_pivot.Translate(SkIntToScalar(pivot.x()), SkIntToScalar(pivot.y()));
  265. std::unique_ptr<InterpolatedTransform> pre_transform =
  266. std::make_unique<InterpolatedConstantTransform>(to_pivot);
  267. std::unique_ptr<InterpolatedTransform> post_transform =
  268. std::make_unique<InterpolatedConstantTransform>(from_pivot);
  269. xform->SetChild(std::move(post_transform));
  270. pre_transform->SetChild(std::move(xform));
  271. transform_ = std::move(pre_transform);
  272. }
  273. InterpolatedMatrixTransform::InterpolatedMatrixTransform(
  274. const gfx::Transform& start_transform,
  275. const gfx::Transform& end_transform)
  276. : InterpolatedTransform() {
  277. Init(start_transform, end_transform);
  278. }
  279. InterpolatedMatrixTransform::InterpolatedMatrixTransform(
  280. const gfx::Transform& start_transform,
  281. const gfx::Transform& end_transform,
  282. float start_time,
  283. float end_time)
  284. : InterpolatedTransform() {
  285. Init(start_transform, end_transform);
  286. }
  287. InterpolatedMatrixTransform::~InterpolatedMatrixTransform() {}
  288. gfx::Transform
  289. InterpolatedMatrixTransform::InterpolateButDoNotCompose(float t) const {
  290. gfx::DecomposedTransform blended =
  291. gfx::BlendDecomposedTransforms(end_decomp_, start_decomp_, t);
  292. return gfx::ComposeTransform(blended);
  293. }
  294. void InterpolatedMatrixTransform::Init(const gfx::Transform& start_transform,
  295. const gfx::Transform& end_transform) {
  296. bool success = gfx::DecomposeTransform(&start_decomp_, start_transform);
  297. DCHECK(success);
  298. success = gfx::DecomposeTransform(&end_decomp_, end_transform);
  299. DCHECK(success);
  300. }
  301. } // namespace ui