/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include namespace android { namespace compositionengine { // Geometrical space to which content is projected. // For example, this can be the layer space or the physical display space. class ProjectionSpace { public: ProjectionSpace() = default; ProjectionSpace(ui::Size size, Rect content) : mBounds(size), mContent(std::move(content)) {} // Returns a transform which maps this.content into destination.content // and also rotates according to this.orientation and destination.orientation ui::Transform getTransform(const ProjectionSpace& destination) const { ui::Rotation rotation = destination.getOrientation() - mOrientation; // Compute a transformation which rotates the destination in a way it has the same // orientation as us. const uint32_t inverseRotationFlags = ui::Transform::toRotationFlags(-rotation); ui::Transform inverseRotatingTransform; inverseRotatingTransform.set(inverseRotationFlags, destination.getBounds().width, destination.getBounds().height); // The destination content rotated so it has the same orientation as us. Rect orientedDestContent = inverseRotatingTransform.transform(destination.getContent()); // Compute translation from the source content to (0, 0). const float sourceX = mContent.left; const float sourceY = mContent.top; ui::Transform sourceTranslation; sourceTranslation.set(-sourceX, -sourceY); // Compute scaling transform which maps source content to destination content, assuming // they are both at (0, 0). ui::Transform scale; const float scaleX = static_cast(orientedDestContent.width()) / mContent.width(); const float scaleY = static_cast(orientedDestContent.height()) / mContent.height(); scale.set(scaleX, 0, 0, scaleY); // Compute translation from (0, 0) to the orientated destination content. const float destX = orientedDestContent.left; const float destY = orientedDestContent.top; ui::Transform destTranslation; destTranslation.set(destX, destY); // Compute rotation transform. const uint32_t orientationFlags = ui::Transform::toRotationFlags(rotation); auto orientedDestWidth = destination.getBounds().width; auto orientedDestHeight = destination.getBounds().height; if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) { std::swap(orientedDestWidth, orientedDestHeight); } ui::Transform rotationTransform; rotationTransform.set(orientationFlags, orientedDestWidth, orientedDestHeight); // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation. // Apply the logical translation, scale to physical size, apply the // physical translation and finally rotate to the physical orientation. return rotationTransform * destTranslation * scale * sourceTranslation; } bool operator==(const ProjectionSpace& other) const { return mBounds == other.mBounds && mContent == other.mContent && mOrientation == other.mOrientation; } void setBounds(ui::Size newBounds) { mBounds = std::move(newBounds); } void setContent(Rect newContent) { mContent = std::move(newContent); } void setOrientation(ui::Rotation newOrientation) { mOrientation = newOrientation; } Rect getBoundsAsRect() const { return Rect(mBounds.getWidth(), mBounds.getHeight()); } const ui::Size& getBounds() const { return mBounds; } const Rect& getContent() const { return mContent; } ui::Rotation getOrientation() const { return mOrientation; } private: // Bounds of this space. Always starts at (0,0). ui::Size mBounds = ui::Size(); // Rect onto which content is projected. Rect mContent = Rect(); // The orientation of this space. This value is meaningful only in relation to the rotation // of another projection space and it's used to determine the rotating transformation when // mapping between the two. // As a convention when using this struct orientation = 0 for the "oriented*" projection // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation // of the display space will become 90, while the orientation of the layer stack space will // remain the same. ui::Rotation mOrientation = ui::ROTATION_0; }; } // namespace compositionengine inline std::string to_string(const compositionengine::ProjectionSpace& space) { return base::StringPrintf("ProjectionSpace{bounds=%s, content=%s, orientation=%s}", to_string(space.getBoundsAsRect()).c_str(), to_string(space.getContent()).c_str(), toCString(space.getOrientation())); } // Defining PrintTo helps with Google Tests. inline void PrintTo(const compositionengine::ProjectionSpace& space, std::ostream* os) { *os << to_string(space); } } // namespace android