|  | // Copyright 2019 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "ui/gfx/overlay_transform_utils.h" | 
|  |  | 
|  | #include "base/notreached.h" | 
|  | #include "ui/gfx/geometry/rect_conversions.h" | 
|  |  | 
|  | namespace gfx { | 
|  |  | 
|  | Transform OverlayTransformToTransform(OverlayTransform overlay_transform, | 
|  | const SizeF& viewport_bounds) { | 
|  | switch (overlay_transform) { | 
|  | case OVERLAY_TRANSFORM_INVALID: | 
|  | NOTREACHED(); | 
|  | case OVERLAY_TRANSFORM_NONE: | 
|  | return Transform(); | 
|  | case OVERLAY_TRANSFORM_FLIP_HORIZONTAL: | 
|  | return Transform::Affine(-1, 0, 0, 1, viewport_bounds.width(), 0); | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL: | 
|  | return Transform::Affine(1, 0, 0, -1, 0, viewport_bounds.height()); | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90: | 
|  | return Transform::Affine(0, 1, -1, 0, viewport_bounds.height(), 0); | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_180: | 
|  | return Transform::Affine(-1, 0, 0, -1, viewport_bounds.width(), | 
|  | viewport_bounds.height()); | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270: | 
|  | return Transform::Affine(0, -1, 1, 0, 0, viewport_bounds.width()); | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_90: | 
|  | return Transform::Affine(0, 1, 1, 0, 0, 0); | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_270: | 
|  | return Transform::Affine(0, -1, -1, 0, viewport_bounds.height(), | 
|  | viewport_bounds.width()); | 
|  | } | 
|  |  | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | OverlayTransform InvertOverlayTransform(OverlayTransform transform) { | 
|  | switch (transform) { | 
|  | case OVERLAY_TRANSFORM_INVALID: | 
|  | NOTREACHED(); | 
|  | case OVERLAY_TRANSFORM_NONE: | 
|  | return OVERLAY_TRANSFORM_NONE; | 
|  | case OVERLAY_TRANSFORM_FLIP_HORIZONTAL: | 
|  | return OVERLAY_TRANSFORM_FLIP_HORIZONTAL; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL: | 
|  | return OVERLAY_TRANSFORM_FLIP_VERTICAL; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90: | 
|  | return OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_180: | 
|  | return OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_180; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270: | 
|  | return OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_90: | 
|  | return OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_90; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_270: | 
|  | return OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_270; | 
|  | } | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | OverlayTransform OverlayTransformsConcat(OverlayTransform t1, | 
|  | OverlayTransform t2) { | 
|  | if (t1 == OVERLAY_TRANSFORM_INVALID || t2 == OVERLAY_TRANSFORM_INVALID) { | 
|  | return OVERLAY_TRANSFORM_INVALID; | 
|  | } | 
|  |  | 
|  | enum VFlip { | 
|  | // Written so they behave similar to bools. | 
|  | kNo = 0, | 
|  | kYes, | 
|  | }; | 
|  | enum Rotation { | 
|  | // Enums are written so that it's valid to do modular arithematic. | 
|  | // Eg k90 + k270 mod 4 is k0. | 
|  | k0 = 0, | 
|  | k90, | 
|  | k180, | 
|  | k270, | 
|  | }; | 
|  |  | 
|  | // Step 1: Decompose arguments into vertical flip and clock-wise rotation. | 
|  | struct DecomposedOverlayTransform { | 
|  | VFlip vflip; | 
|  | Rotation rotation; | 
|  | }; | 
|  | auto decompose = [](OverlayTransform t) -> DecomposedOverlayTransform { | 
|  | switch (t) { | 
|  | case OVERLAY_TRANSFORM_NONE: | 
|  | return {VFlip::kNo, Rotation::k0}; | 
|  | case OVERLAY_TRANSFORM_FLIP_HORIZONTAL: | 
|  | return {VFlip::kYes, Rotation::k180}; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL: | 
|  | return {VFlip::kYes, Rotation::k0}; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90: | 
|  | return {VFlip::kNo, Rotation::k90}; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_180: | 
|  | return {VFlip::kNo, Rotation::k180}; | 
|  | case OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270: | 
|  | return {VFlip::kNo, Rotation::k270}; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_90: | 
|  | return {VFlip::kYes, Rotation::k90}; | 
|  | case OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_270: | 
|  | return {VFlip::kYes, Rotation::k270}; | 
|  | case OVERLAY_TRANSFORM_INVALID: | 
|  | break; | 
|  | } | 
|  | NOTREACHED(); | 
|  | }; | 
|  |  | 
|  | DecomposedOverlayTransform decomposed1 = decompose(t1); | 
|  | DecomposedOverlayTransform decomposed2 = decompose(t2); | 
|  |  | 
|  | // Step 2: Compute decomposed result. | 
|  | // Result flip is effectively an XOR of two arguments. | 
|  | VFlip result_vflip = | 
|  | static_cast<VFlip>(decomposed1.vflip != decomposed2.vflip); | 
|  | // Add rotation, except that rotation of `t1` needs to be subtracted if `t2` | 
|  | // contains a flip. | 
|  | Rotation result_rotation; | 
|  | if (decomposed2.vflip == VFlip::kYes) { | 
|  | result_rotation = static_cast<Rotation>( | 
|  | (decomposed2.rotation + 4 - decomposed1.rotation) % 4); | 
|  | } else { | 
|  | result_rotation = static_cast<Rotation>( | 
|  | (decomposed2.rotation + decomposed1.rotation) % 4); | 
|  | } | 
|  |  | 
|  | // Step 3: Reconstruct result. | 
|  | switch (result_rotation) { | 
|  | case Rotation::k0: | 
|  | return result_vflip == VFlip::kYes ? OVERLAY_TRANSFORM_FLIP_VERTICAL | 
|  | : OVERLAY_TRANSFORM_NONE; | 
|  | case Rotation::k90: | 
|  | return result_vflip == VFlip::kYes | 
|  | ? OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_90 | 
|  | : OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_90; | 
|  | case Rotation::k180: | 
|  | return result_vflip == VFlip::kYes | 
|  | ? OVERLAY_TRANSFORM_FLIP_HORIZONTAL | 
|  | : OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_180; | 
|  | case Rotation::k270: | 
|  | return result_vflip == VFlip::kYes | 
|  | ? OVERLAY_TRANSFORM_FLIP_VERTICAL_CLOCKWISE_270 | 
|  | : OVERLAY_TRANSFORM_ROTATE_CLOCKWISE_270; | 
|  | } | 
|  |  | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | }  // namespace gfx |