/*
 * Copyright (C) 2016 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.
 */

#include <sstream>
#include <cutils/log.h>
#include <ui/Rect.h>

#define HWC2_INCLUDE_STRINGIFICATION
#define HWC2_USE_CPP11
#include <hardware/hwcomposer2.h>
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11

#include "Hwc2TestBuffer.h"
#include "Hwc2TestProperties.h"

Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage,
        const Area& displayArea)
    : Hwc2TestProperty(mBufferAreas, mCompositionSupport),
      mScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteScalars:
            (coverage == Hwc2TestCoverage::Basic)? mBasicScalars:
            mDefaultScalars),
      mDisplayArea(displayArea)
{
    update();
}

std::string Hwc2TestBufferArea::dump() const
{
    std::stringstream dmp;
    const Area& curr = get();
    dmp << "\tbuffer area: width " << curr.width << ", height " << curr.height
            << "\n";
    return dmp.str();
}

void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer)
{
    mBuffer = buffer;
    if (buffer) {
        buffer->updateBufferArea(get());
    }
}

void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop)
{
    mSourceCrop = sourceCrop;
    if (mSourceCrop) {
        mSourceCrop->updateBufferArea(get());
    }
}

void Hwc2TestBufferArea::setDependent(Hwc2TestSurfaceDamage* surfaceDamage)
{
    mSurfaceDamage = surfaceDamage;
    if (mSurfaceDamage) {
        mSurfaceDamage->updateBufferArea(get());
    }
}

void Hwc2TestBufferArea::update()
{
    mBufferAreas.clear();

    if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
        mBufferAreas.push_back({0, 0});
        return;
    }

    for (auto scalar : mScalars) {
        mBufferAreas.push_back({static_cast<int32_t>(scalar * mDisplayArea.width),
                static_cast<int32_t>(scalar * mDisplayArea.height)});
    }

    updateDependents();
}

void Hwc2TestBufferArea::updateDependents()
{
    const Area& curr = get();

    if (mBuffer)
        mBuffer->updateBufferArea(curr);
    if (mSourceCrop)
        mSourceCrop->updateBufferArea(curr);
    if (mSurfaceDamage)
        mSurfaceDamage->updateBufferArea(curr);
}

const std::vector<float> Hwc2TestBufferArea::mDefaultScalars = {
    1.0f,
};

const std::vector<float> Hwc2TestBufferArea::mBasicScalars = {
    1.0f, 0.5f,
};

const std::vector<float> Hwc2TestBufferArea::mCompleteScalars = {
    1.0f, 0.75f, 0.5f
};


Hwc2TestBlendMode::Hwc2TestBlendMode(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(coverage, mCompleteBlendModes, mBasicBlendModes,
            mDefaultBlendModes, mCompositionSupport) { }

std::string Hwc2TestBlendMode::dump() const
{
    std::stringstream dmp;
    dmp << "\tblend mode: " << getBlendModeName(get()) << "\n";
    return dmp.str();
}

void Hwc2TestBlendMode::setDependent(Hwc2TestColor* color)
{
    mColor = color;
    updateDependents();
}

void Hwc2TestBlendMode::updateDependents()
{
    if (mColor)
        mColor->updateBlendMode(get());
}

const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mDefaultBlendModes = {
    HWC2_BLEND_MODE_NONE,
};

const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mBasicBlendModes = {
    HWC2_BLEND_MODE_NONE,
    HWC2_BLEND_MODE_PREMULTIPLIED,
};

const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mCompleteBlendModes = {
    HWC2_BLEND_MODE_NONE,
    HWC2_BLEND_MODE_PREMULTIPLIED,
    HWC2_BLEND_MODE_COVERAGE,
};


Hwc2TestColor::Hwc2TestColor(Hwc2TestCoverage coverage,
        hwc2_blend_mode_t blendMode)
    : Hwc2TestProperty(mColors, mCompositionSupport),
      mBaseColors((coverage == Hwc2TestCoverage::Complete)? mCompleteBaseColors:
            (coverage == Hwc2TestCoverage::Basic)? mBasicBaseColors:
            mDefaultBaseColors),
      mBlendMode(blendMode)
{
    update();
}

std::string Hwc2TestColor::dump() const
{
    std::stringstream dmp;
    const hwc_color_t& color = get();
    dmp << "\tcolor: r " << std::to_string(color.r) << ", g "
            << std::to_string(color.g) << ", b " << std::to_string(color.b)
            << ", a " << std::to_string(color.a) << "\n";
    return dmp.str();
}

void Hwc2TestColor::updateBlendMode(hwc2_blend_mode_t blendMode)
{
    mBlendMode = blendMode;
    update();
}

void Hwc2TestColor::update()
{
    if (mBlendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
        mColors = mBaseColors;
        return;
    }

    mColors.clear();

    for (const hwc_color_t& baseColor : mBaseColors) {
        if (baseColor.a >= baseColor.r && baseColor.a >= baseColor.g
                && baseColor.a >= baseColor.b) {
            mColors.push_back(baseColor);
        }
    }

}

const std::vector<hwc_color_t> Hwc2TestColor::mDefaultBaseColors = {
    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
};

const std::vector<hwc_color_t> Hwc2TestColor::mBasicBaseColors = {
    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
    {        0,         0,         0,         0},
};

const std::vector<hwc_color_t> Hwc2TestColor::mCompleteBaseColors = {
    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
    {UINT8_MAX, UINT8_MAX, UINT8_MAX,         0},
    {UINT8_MAX, UINT8_MAX,         0, UINT8_MAX},
    {UINT8_MAX, UINT8_MAX,         0,         0},
    {UINT8_MAX,         0, UINT8_MAX, UINT8_MAX},
    {UINT8_MAX,         0, UINT8_MAX,         0},
    {UINT8_MAX,         0,         0, UINT8_MAX},
    {UINT8_MAX,         0,         0,         0},
    {        0, UINT8_MAX, UINT8_MAX, UINT8_MAX},
    {        0, UINT8_MAX, UINT8_MAX,         0},
    {        0, UINT8_MAX,         0, UINT8_MAX},
    {        0, UINT8_MAX,         0,         0},
    {        0,         0, UINT8_MAX, UINT8_MAX},
    {        0,         0, UINT8_MAX,         0},
    {        0,         0,         0, UINT8_MAX},
    {        0,         0,         0,         0},
};


Hwc2TestComposition::Hwc2TestComposition(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(coverage, mCompleteCompositions, mBasicCompositions,
            mDefaultCompositions, mCompositionSupport) { }

std::string Hwc2TestComposition::dump() const
{
    std::stringstream dmp;
    dmp << "\tcomposition: " << getCompositionName(get()) << "\n";
    return dmp.str();
}

const std::vector<hwc2_composition_t> Hwc2TestComposition::mDefaultCompositions = {
    HWC2_COMPOSITION_DEVICE,
};

const std::vector<hwc2_composition_t> Hwc2TestComposition::mBasicCompositions = {
    HWC2_COMPOSITION_CLIENT,
    HWC2_COMPOSITION_DEVICE,
};

const std::vector<hwc2_composition_t> Hwc2TestComposition::mCompleteCompositions = {
    HWC2_COMPOSITION_CLIENT,
    HWC2_COMPOSITION_DEVICE,
    HWC2_COMPOSITION_SOLID_COLOR,
    HWC2_COMPOSITION_CURSOR,
    HWC2_COMPOSITION_SIDEBAND,
};


Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(coverage, completeDataspaces, basicDataspaces,
            defaultDataspaces, mCompositionSupport) { }

std::string Hwc2TestDataspace::dump() const
{
    std::stringstream dmp;
    dmp << "\tdataspace: " << get() << "\n";
    return dmp.str();
}

const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = {
    HAL_DATASPACE_UNKNOWN,
};

const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = {
    HAL_DATASPACE_UNKNOWN,
    HAL_DATASPACE_V0_SRGB,
};

const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = {
    HAL_DATASPACE_UNKNOWN,
    HAL_DATASPACE_ARBITRARY,
    HAL_DATASPACE_STANDARD_SHIFT,
    HAL_DATASPACE_STANDARD_MASK,
    HAL_DATASPACE_STANDARD_UNSPECIFIED,
    HAL_DATASPACE_STANDARD_BT709,
    HAL_DATASPACE_STANDARD_BT601_625,
    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED,
    HAL_DATASPACE_STANDARD_BT601_525,
    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED,
    HAL_DATASPACE_STANDARD_BT2020,
    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE,
    HAL_DATASPACE_STANDARD_BT470M,
    HAL_DATASPACE_STANDARD_FILM,
    HAL_DATASPACE_TRANSFER_SHIFT,
    HAL_DATASPACE_TRANSFER_MASK,
    HAL_DATASPACE_TRANSFER_UNSPECIFIED,
    HAL_DATASPACE_TRANSFER_LINEAR,
    HAL_DATASPACE_TRANSFER_SRGB,
    HAL_DATASPACE_TRANSFER_SMPTE_170M,
    HAL_DATASPACE_TRANSFER_GAMMA2_2,
    HAL_DATASPACE_TRANSFER_GAMMA2_8,
    HAL_DATASPACE_TRANSFER_ST2084,
    HAL_DATASPACE_TRANSFER_HLG,
    HAL_DATASPACE_RANGE_SHIFT,
    HAL_DATASPACE_RANGE_MASK,
    HAL_DATASPACE_RANGE_UNSPECIFIED,
    HAL_DATASPACE_RANGE_FULL,
    HAL_DATASPACE_RANGE_LIMITED,
    HAL_DATASPACE_SRGB_LINEAR,
    HAL_DATASPACE_V0_SRGB_LINEAR,
    HAL_DATASPACE_SRGB,
    HAL_DATASPACE_V0_SRGB,
    HAL_DATASPACE_JFIF,
    HAL_DATASPACE_V0_JFIF,
    HAL_DATASPACE_BT601_625,
    HAL_DATASPACE_V0_BT601_625,
    HAL_DATASPACE_BT601_525,
    HAL_DATASPACE_V0_BT601_525,
    HAL_DATASPACE_BT709,
    HAL_DATASPACE_V0_BT709,
    HAL_DATASPACE_DEPTH,
};


Hwc2TestDisplayDimension::Hwc2TestDisplayDimension(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(
            (coverage == Hwc2TestCoverage::Complete)? mCompleteDisplayDimensions:
            (coverage == Hwc2TestCoverage::Basic)? mBasicDisplayDimensions:
            mDefaultDisplayDimensions, mCompositionSupport) { }

std::string Hwc2TestDisplayDimension::dump() const
{
    std::stringstream dmp;
    const UnsignedArea& curr = get();
    dmp << "\tdisplay dimension: " << curr.width<< " x " << curr.height<< "\n";
    return dmp.str();
}

void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer)
{
    mBuffer = buffer;
    updateDependents();
}

void Hwc2TestDisplayDimension::updateDependents()
{
    const UnsignedArea& curr = get();

    if (mBuffer)
        mBuffer->updateBufferArea({static_cast<int32_t>(curr.width),
                static_cast<int32_t>(curr.height)});
}

const std::vector<UnsignedArea>
        Hwc2TestDisplayDimension::mDefaultDisplayDimensions = {
    {1920, 1080},
};

const std::vector<UnsignedArea>
        Hwc2TestDisplayDimension::mBasicDisplayDimensions = {
    {640, 480},
    {1280, 720},
    {1920, 1080},
    {1920, 1200},
};

const std::vector<UnsignedArea>
        Hwc2TestDisplayDimension::mCompleteDisplayDimensions = {
    {320, 240},
    {480, 320},
    {640, 480},
    {1280, 720},
    {1920, 1080},
    {1920, 1200},
    {2560, 1440},
    {2560, 1600},
    {3840, 2160},
    {4096, 2160},
};


Hwc2TestDisplayFrame::Hwc2TestDisplayFrame(Hwc2TestCoverage coverage,
        const Area& displayArea)
    : Hwc2TestProperty(mDisplayFrames, mCompositionSupport),
      mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
            (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
            mDefaultFrectScalars),
      mDisplayArea(displayArea)
{
    update();
}

std::string Hwc2TestDisplayFrame::dump() const
{
    std::stringstream dmp;
    const hwc_rect_t& displayFrame = get();
    dmp << "\tdisplay frame: left " << displayFrame.left << ", top "
            << displayFrame.top << ", right " << displayFrame.right
            << ", bottom " << displayFrame.bottom << "\n";
    return dmp.str();
}

void Hwc2TestDisplayFrame::update()
{
    mDisplayFrames.clear();

    if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
        mDisplayFrames.push_back({0, 0, 0, 0});
        return;
    }

    for (const auto& frectScalar : mFrectScalars) {
        mDisplayFrames.push_back({
                static_cast<int>(frectScalar.left * mDisplayArea.width),
                static_cast<int>(frectScalar.top * mDisplayArea.height),
                static_cast<int>(frectScalar.right * mDisplayArea.width),
                static_cast<int>(frectScalar.bottom * mDisplayArea.height)});
    }
}

const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mDefaultFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
};

const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mBasicFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
    {0.0, 0.0, 1.0, 0.05},
    {0.0, 0.95, 1.0, 1.0},
};

const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mCompleteFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
    {0.0, 0.05, 1.0, 0.95},
    {0.0, 0.05, 1.0, 1.0},
    {0.0, 0.0, 1.0, 0.05},
    {0.0, 0.95, 1.0, 1.0},
    {0.25, 0.0, 0.75, 0.35},
    {0.25, 0.25, 0.75, 0.75},
};


Hwc2TestPlaneAlpha::Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(coverage, mCompletePlaneAlphas, mBasicPlaneAlphas,
            mDefaultPlaneAlphas, mCompositionSupport) { }

std::string Hwc2TestPlaneAlpha::dump() const
{
    std::stringstream dmp;
    dmp << "\tplane alpha: " << get() << "\n";
    return dmp.str();
}

const std::vector<float> Hwc2TestPlaneAlpha::mDefaultPlaneAlphas = {
    1.0f,
};

const std::vector<float> Hwc2TestPlaneAlpha::mBasicPlaneAlphas = {
    1.0f, 0.0f,
};

const std::vector<float> Hwc2TestPlaneAlpha::mCompletePlaneAlphas = {
    1.0f, 0.75f, 0.5f, 0.25f, 0.0f,
};


Hwc2TestSourceCrop::Hwc2TestSourceCrop(Hwc2TestCoverage coverage,
        const Area& bufferArea)
    : Hwc2TestProperty(mSourceCrops, mCompositionSupport),
      mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
            (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
            mDefaultFrectScalars),
      mBufferArea(bufferArea)
{
    update();
}

std::string Hwc2TestSourceCrop::dump() const
{
    std::stringstream dmp;
    const hwc_frect_t& sourceCrop = get();
    dmp << "\tsource crop: left " << sourceCrop.left << ", top "
            << sourceCrop.top << ", right " << sourceCrop.right << ", bottom "
            << sourceCrop.bottom << "\n";
    return dmp.str();
}

void Hwc2TestSourceCrop::updateBufferArea(const Area& bufferArea)
{
    mBufferArea = bufferArea;
    update();
}

void Hwc2TestSourceCrop::update()
{
    mSourceCrops.clear();

    if (mBufferArea.width == 0 && mBufferArea.height == 0) {
        mSourceCrops.push_back({0, 0, 0, 0});
        return;
    }

    for (const auto& frectScalar : mFrectScalars) {
        mSourceCrops.push_back({
                frectScalar.left * mBufferArea.width,
                frectScalar.top * mBufferArea.height,
                frectScalar.right * mBufferArea.width,
                frectScalar.bottom * mBufferArea.height});
    }
}

const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mDefaultFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
};

const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mBasicFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
    {0.0, 0.0, 0.5, 0.5},
    {0.5, 0.5, 1.0, 1.0},
};

const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mCompleteFrectScalars = {
    {0.0, 0.0, 1.0, 1.0},
    {0.0, 0.0, 0.5, 0.5},
    {0.5, 0.5, 1.0, 1.0},
    {0.0, 0.0, 0.25, 0.25},
    {0.25, 0.25, 0.75, 0.75},
};


Hwc2TestSurfaceDamage::Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(mSurfaceDamages, mCompositionSupport),
      mRegionScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteRegionScalars:
            (coverage == Hwc2TestCoverage::Basic)? mBasicRegionScalars:
            mDefaultRegionScalars)
{
    update();
}

Hwc2TestSurfaceDamage::~Hwc2TestSurfaceDamage()
{
    freeSurfaceDamages();
}

std::string Hwc2TestSurfaceDamage::dump() const
{
    std::stringstream dmp;

    const hwc_region_t& curr = get();
    dmp << "\tsurface damage: region count " << curr.numRects << "\n";
    for (size_t i = 0; i < curr.numRects; i++) {
        const hwc_rect_t& rect = curr.rects[i];
        dmp << "\t\trect: left " << rect.left << ", top " << rect.top
                << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
    }

    return dmp.str();
}

void Hwc2TestSurfaceDamage::updateBufferArea(const Area& bufferArea)
{
    mBufferArea = bufferArea;
    update();
}

void Hwc2TestSurfaceDamage::update()
{
    freeSurfaceDamages();

    if (mBufferArea.width == 0 && mBufferArea.height == 0) {
        mSurfaceDamages.push_back({0, nullptr});
        return;
    }

    hwc_region_t damage;

    for (const auto& regionScalar : mRegionScalars) {
        damage.numRects = regionScalar.size();

        if (damage.numRects > 0) {
            hwc_rect_t* rects = new hwc_rect_t[damage.numRects];
            if (!rects) {
                ALOGW("failed to allocate new hwc_rect_t array");
                continue;
            }

            for (size_t i = 0; i < damage.numRects; i++) {
                rects[i].left = regionScalar[i].left * mBufferArea.width;
                rects[i].top = regionScalar[i].top * mBufferArea.height;
                rects[i].right = regionScalar[i].right * mBufferArea.width;
                rects[i].bottom = regionScalar[i].bottom * mBufferArea.height;
            }

            damage.rects = static_cast<hwc_rect_t const*>(rects);
        } else {
            damage.rects = nullptr;
        }

        mSurfaceDamages.push_back(damage);
    }
}

void Hwc2TestSurfaceDamage::freeSurfaceDamages()
{
    for (const auto& surfaceDamage : mSurfaceDamages) {
        if (surfaceDamage.numRects > 0 && surfaceDamage.rects)
            delete[] surfaceDamage.rects;
    }
    mSurfaceDamages.clear();
}

const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mDefaultRegionScalars = {
    {{}},
};

const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mBasicRegionScalars = {
    {{}},
    {{0.0, 0.0, 1.0, 1.0}},
};

const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mCompleteRegionScalars = {
    {{}},
    {{0.0, 0.0, 1.0, 1.0}},
    {{0.0, 0.0, 0.5, 0.5}, {0.5, 0.5, 1.0, 1.0}},
};


Hwc2TestTransform::Hwc2TestTransform(Hwc2TestCoverage coverage)
    : Hwc2TestProperty(coverage, mCompleteTransforms, mBasicTransforms,
            mDefaultTransforms, mCompositionSupport) { }

std::string Hwc2TestTransform::dump() const
{
    std::stringstream dmp;
    dmp << "\ttransform: " << getTransformName(get()) << "\n";
    return dmp.str();
}

const std::vector<hwc_transform_t> Hwc2TestTransform::mDefaultTransforms = {
    static_cast<hwc_transform_t>(0),
};

const std::vector<hwc_transform_t> Hwc2TestTransform::mBasicTransforms = {
    static_cast<hwc_transform_t>(0),
    HWC_TRANSFORM_FLIP_H,
    HWC_TRANSFORM_FLIP_V,
    HWC_TRANSFORM_ROT_90,
};

const std::vector<hwc_transform_t> Hwc2TestTransform::mCompleteTransforms = {
    static_cast<hwc_transform_t>(0),
    HWC_TRANSFORM_FLIP_H,
    HWC_TRANSFORM_FLIP_V,
    HWC_TRANSFORM_ROT_90,
    HWC_TRANSFORM_ROT_180,
    HWC_TRANSFORM_ROT_270,
    HWC_TRANSFORM_FLIP_H_ROT_90,
    HWC_TRANSFORM_FLIP_V_ROT_90,
};


Hwc2TestVisibleRegion::~Hwc2TestVisibleRegion()
{
    release();
}

std::string Hwc2TestVisibleRegion::dump() const
{
    std::stringstream dmp;

    const hwc_region_t& curr = get();
    dmp << "\tvisible region: region count " << curr.numRects << "\n";
    for (size_t i = 0; i < curr.numRects; i++) {
        const hwc_rect_t& rect = curr.rects[i];
        dmp << "\t\trect: left " << rect.left << ", top " << rect.top
                << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
    }

    return dmp.str();
}

void Hwc2TestVisibleRegion::set(const android::Region& visibleRegion)
{
    release();

    size_t size = 0;
    const android::Rect* rects = visibleRegion.getArray(&size);

    mVisibleRegion.numRects = size;
    mVisibleRegion.rects = nullptr;

    if (size > 0) {
        hwc_rect_t* hwcRects = new hwc_rect_t[size];
        for (size_t i = 0; i < size; i++) {
            hwcRects[i].left = rects[i].left;
            hwcRects[i].top = rects[i].top;
            hwcRects[i].right = rects[i].right;
            hwcRects[i].bottom = rects[i].bottom;
        }
        mVisibleRegion.rects = hwcRects;
    }
}

hwc_region_t Hwc2TestVisibleRegion::get() const
{
    return mVisibleRegion;
}

void Hwc2TestVisibleRegion::release()
{
    if (mVisibleRegion.numRects > 0 && mVisibleRegion.rects)
        delete[] mVisibleRegion.rects;
    mVisibleRegion.rects = nullptr;
    mVisibleRegion.numRects = 0;
}

/* Identifies which layer properties are supported by each composition type.
 * hwc2_composition_t values range from:
 *  HWC2_COMPOSITION_INVALID = 0,
 *  HWC2_COMPOSITION_CLIENT = 1,
 *  HWC2_COMPOSITION_DEVICE = 2,
 *  HWC2_COMPOSITION_SOLID_COLOR = 3,
 *  HWC2_COMPOSITION_CURSOR = 4,
 *  HWC2_COMPOSITION_SIDEBAND = 5,
 *
 * Each property array can be indexed by a hwc2_composition_t value.
 * By using an array instead of a more complex data structure, runtimes for
 * some test cases showed a noticeable improvement.
 */

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestBufferArea::mCompositionSupport = {{
    false,   true,    true,    false,   true,    true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestBlendMode::mCompositionSupport = {{
    false,   true,    true,    false,   true,    true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestColor::mCompositionSupport = {{
    false,   false,   false,   true,    false,   false,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestComposition::mCompositionSupport = {{
    false,   true,    true,    true,    true,    true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestDataspace::mCompositionSupport = {{
    false,   true,    true,    true,    true,    false,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestDisplayDimension::mCompositionSupport = {{
    false,   true,    true,    true,    true,    true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestDisplayFrame::mCompositionSupport = {{
    false,   true,    true,    true,    false,   true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestPlaneAlpha::mCompositionSupport = {{
    false,   true,    true,    true,    true,    true,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestSourceCrop::mCompositionSupport = {{
    false,   true,    true,    false,   true,    false,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestSurfaceDamage::mCompositionSupport = {{
    false,   false,   true,    false,   true,    false,
}};

/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
    false,   true,    true,    false,   true,    true,
}};
