From 578dc5345d82bdb0762722ba317d9d74b3f744c1 Mon Sep 17 00:00:00 2001 From: Diego Wilson Date: Wed, 14 Aug 2013 12:26:44 -0700 Subject: [PATCH] Bug 903562 - Honor horizontal and vertical reflection. r=ncameron, r=vliu --- widget/gonk/HwcComposer2D.cpp | 129 +++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index 1b5c7d2c0f7..fda8a1dad10 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2012, 2013 The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -319,6 +319,15 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer, return true; } + // HWC supports only the following 2D transformations: + // + // Scaling via the sourceCrop and displayFrame in hwc_layer_t + // Translation via the sourceCrop and displayFrame in hwc_layer_t + // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags + // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags + // + // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes + // above gfxMatrix transform; const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform(); if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { @@ -356,6 +365,8 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer, return false; } } + // Buffer rotation is not to be confused with the angled rotation done by a transform matrix + // It's a fancy ThebesLayer feature used for scrolling if (state.BufferRotated()) { LOGD("%s Layer has a rotated buffer", aLayer->Name()); return false; @@ -413,24 +424,122 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer, hwcLayer.flags |= HWC_FORMAT_RB_SWAP; } + // Translation and scaling have been addressed in PrepareLayerRects(). + // Given the above and that we checked for PreservesAxisAlignedRectangles() + // the only possible transformations left to address are + // square angle rotation and horizontal/vertical reflection. + // + // The rotation and reflection permutations total 16 but can be + // reduced to 8 transformations after eliminating redundancies. + // + // All matrices represented here are in the form + // + // | xx xy | + // | yx yy | + // + // And ignore scaling. + // + // Reflection is applied before rotation gfxMatrix rotation = transform * aGLWorldTransform; - // Compute fuzzy equal like PreservesAxisAlignedRectangles() + // Compute fuzzy zero like PreservesAxisAlignedRectangles() if (fabs(rotation.xx) < 1e-6) { if (rotation.xy < 0) { - hwcLayer.transform = HWC_TRANSFORM_ROT_90; - LOGD("Layer buffer rotated 90 degrees"); + if (rotation.yx > 0) { + // 90 degree rotation + // + // | 0 -1 | + // | 1 0 | + // + hwcLayer.transform = HWC_TRANSFORM_ROT_90; + LOGD("Layer rotated 90 degrees"); + } + else { + // Horizontal reflection then 90 degree rotation + // + // | 0 -1 | | -1 0 | = | 0 -1 | + // | 1 0 | | 0 1 | | -1 0 | + // + // same as vertical reflection then 270 degree rotation + // + // | 0 1 | | 1 0 | = | 0 -1 | + // | -1 0 | | 0 -1 | | -1 0 | + // + hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; + LOGD("Layer vertically reflected then rotated 270 degrees"); + } } else { - hwcLayer.transform = HWC_TRANSFORM_ROT_270; - LOGD("Layer buffer rotated 270 degrees"); + if (rotation.yx < 0) { + // 270 degree rotation + // + // | 0 1 | + // | -1 0 | + // + hwcLayer.transform = HWC_TRANSFORM_ROT_270; + LOGD("Layer rotated 270 degrees"); + } + else { + // Vertical reflection then 90 degree rotation + // + // | 0 1 | | -1 0 | = | 0 1 | + // | -1 0 | | 0 1 | | 1 0 | + // + // Same as horizontal reflection then 270 degree rotation + // + // | 0 -1 | | 1 0 | = | 0 1 | + // | 1 0 | | 0 -1 | | 1 0 | + // + hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; + LOGD("Layer horizontally reflected then rotated 270 degrees"); + } } } else if (rotation.xx < 0) { - hwcLayer.transform = HWC_TRANSFORM_ROT_180; - LOGD("Layer buffer rotated 180 degrees"); + if (rotation.yy > 0) { + // Horizontal reflection + // + // | -1 0 | + // | 0 1 | + // + hwcLayer.transform = HWC_TRANSFORM_FLIP_H; + LOGD("Layer rotated 180 degrees"); + } + else { + // 180 degree rotation + // + // | -1 0 | + // | 0 -1 | + // + // Same as horizontal and vertical reflection + // + // | -1 0 | | 1 0 | = | -1 0 | + // | 0 1 | | 0 -1 | | 0 -1 | + // + hwcLayer.transform = HWC_TRANSFORM_ROT_180; + LOGD("Layer rotated 180 degrees"); + } } else { - hwcLayer.transform = 0; + if (rotation.yy < 0) { + // Vertical reflection + // + // | 1 0 | + // | 0 -1 | + // + hwcLayer.transform = HWC_TRANSFORM_FLIP_V; + LOGD("Layer rotated 180 degrees"); + } + else { + // No rotation or reflection + // + // | 1 0 | + // | 0 1 | + // + hwcLayer.transform = 0; + } } - hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0; + if (state.YFlipped()) { + // Invert vertical reflection flag if it was already set + hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; + } hwc_region_t region; if (visibleRegion.GetNumRects() > 1) { mVisibleRegions.push_back(RectVector());