/*
    SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek@kde.org>

    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
 */

#include "kiconutilstest.h"
#include <kiconutils.h>

#include <QIcon>
#include <QPainter>
#include <QPixmap>
#include <QTest>

QTEST_MAIN(KIconUtilsTest)

void KIconUtilsTest::addOverlayTest()
{
    QPixmap rectanglePixmap(32, 32);
    rectanglePixmap.fill(Qt::red);

    QIcon icon(rectanglePixmap);

    QPixmap overlay(32, 32);
    overlay.fill(Qt::blue);

    QIcon overlayIcon(overlay);

    QIcon iconWithOverlay = KIconUtils::addOverlay(icon, overlayIcon, Qt::BottomRightCorner);
    QImage result = iconWithOverlay.pixmap(32, 32).toImage();

    int bluePixels = 0;
    int redPixels = 0;

    // Go over the image and count red and blue pixels
    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            if (qRed(result.pixel(x, y)) == 255) {
                redPixels++;
            } else if (qBlue(result.pixel(x, y)) == 255) {
                bluePixels++;
            }
        }
    }

    // For icon of size 32x32, the overlay should be 16x16 (=256)
    QCOMPARE(redPixels / (result.devicePixelRatio() * result.devicePixelRatio()), 768);
    QCOMPARE(bluePixels / (result.devicePixelRatio() * result.devicePixelRatio()), 256);

    // Try different size and position
    rectanglePixmap = rectanglePixmap.scaled(96, 96);

    icon = QIcon(rectanglePixmap);

    overlay = overlay.scaled(96, 96);

    overlayIcon = QIcon(overlay);

    iconWithOverlay = KIconUtils::addOverlay(icon, overlayIcon, Qt::BottomRightCorner);

    // Test if unsetting the overlay works;
    // the result should have just one blue square
    iconWithOverlay = KIconUtils::addOverlay(icon, QIcon(), Qt::BottomRightCorner);

    iconWithOverlay = KIconUtils::addOverlay(icon, overlayIcon, Qt::TopLeftCorner);
    result = iconWithOverlay.pixmap(96, 96).toImage();

    bluePixels = 0;
    redPixels = 0;

    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            if (qRed(result.pixel(x, y)) == 255) {
                redPixels++;
            } else if (qBlue(result.pixel(x, y)) == 255) {
                bluePixels++;
            }
        }
    }

    // 96x96 big icon will have 32x32 big overlay (=1024 blue pixels)
    QCOMPARE(bluePixels / (result.devicePixelRatio() * result.devicePixelRatio()), 1024);
    QCOMPARE(redPixels / (result.devicePixelRatio() * result.devicePixelRatio()), 8192);

    // Try paint method
    icon = QIcon(rectanglePixmap);
    iconWithOverlay = KIconUtils::addOverlay(icon, overlayIcon, Qt::TopLeftCorner);

    QPixmap a(96, 96);
    QPainter p(&a);
    iconWithOverlay.paint(&p, a.rect(), Qt::AlignCenter, QIcon::Normal, QIcon::Off);

    result = a.toImage();

    bluePixels = 0;
    redPixels = 0;

    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            if (qRed(result.pixel(x, y)) == 255) {
                redPixels++;
            } else if (qBlue(result.pixel(x, y)) == 255) {
                bluePixels++;
            }
        }
    }

    // 96x96 big icon will have 32x32 big overlay (=1024 blue pixels)
    QCOMPARE(bluePixels, 1024);
    QCOMPARE(redPixels, 8192);
}

void KIconUtilsTest::addOverlaysTest()
{
    QPixmap rectanglePixmap(32, 32);
    rectanglePixmap.fill(Qt::red);

    QIcon icon(rectanglePixmap);

    QPixmap overlay(32, 32);
    overlay.fill(Qt::blue);

    QIcon overlayIcon(overlay);

    QHash<Qt::Corner, QIcon> overlays;
    overlays.insert(Qt::BottomRightCorner, overlayIcon);
    overlays.insert(Qt::TopLeftCorner, overlayIcon);

    QIcon iconWithOverlay = KIconUtils::addOverlays(icon, overlays);
    QImage result = iconWithOverlay.pixmap(32, 32).toImage();

    int bluePixels = 0;
    int redPixels = 0;

    // Go over the image and count red and blue pixels
    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            if (qRed(result.pixel(x, y)) == 255) {
                redPixels++;
            } else if (qBlue(result.pixel(x, y)) == 255) {
                bluePixels++;
            }
        }
    }

    // Two blue overlays in icon size 32x32 would intersect with 16 pixels,
    // so the amount of blue pixels should be 2x256-16 = 496
    QCOMPARE(bluePixels / (result.devicePixelRatio() * result.devicePixelRatio()), 496);
    QCOMPARE(redPixels / (result.devicePixelRatio() * result.devicePixelRatio()), 528);

    // Try different size

    rectanglePixmap = rectanglePixmap.scaled(96, 96);
    icon = QIcon(rectanglePixmap);
    overlay = overlay.scaled(96, 96);
    overlayIcon = QIcon(overlay);

    // Clear the old sizes first
    overlays.clear();
    overlays.insert(Qt::BottomRightCorner, overlayIcon);
    overlays.insert(Qt::TopRightCorner, overlayIcon);
    overlays.insert(Qt::TopLeftCorner, overlayIcon);

    // Now it will have 3 overlays
    iconWithOverlay = KIconUtils::addOverlays(icon, overlays);

    QPixmap a(96, 96);
    QPainter p(&a);
    iconWithOverlay.paint(&p, a.rect(), Qt::AlignCenter, QIcon::Normal, QIcon::Off);

    result = a.toImage();

    bluePixels = 0;
    redPixels = 0;

    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            if (qRed(result.pixel(x, y)) == 255) {
                redPixels++;
            } else if (qBlue(result.pixel(x, y)) == 255) {
                bluePixels++;
            }
        }
    }

    // 96x96 big icon will have 32x32 big overlays (=3072 blue pixels)
    QCOMPARE(bluePixels / (result.devicePixelRatio() * result.devicePixelRatio()), 3072);
    QCOMPARE(redPixels / (result.devicePixelRatio() * result.devicePixelRatio()), 6144);
}

void KIconUtilsTest::addOverlayNonSquareTest()
{
    // A non-square base icon is painted centered and aspect-ratio-preserving, so it
    // does not fill the (square) requested rect. The overlay must hug the icon's
    // corner, not the corner of the rect, otherwise it detaches from the icon.
    QPixmap tall(64, 256);
    tall.fill(Qt::red);
    const QIcon icon(tall);

    QPixmap overlay(64, 64);
    overlay.fill(Qt::blue);
    const QIcon overlayIcon(overlay);

    const QIcon iconWithOverlay = KIconUtils::addOverlay(icon, overlayIcon, Qt::BottomRightCorner);

    QPixmap target(64, 64);
    target.fill(Qt::transparent);
    QPainter p(&target);
    iconWithOverlay.paint(&p, target.rect(), Qt::AlignCenter, QIcon::Normal, QIcon::Off);
    p.end();

    const QImage result = target.toImage();

    // Bounding boxes of the base icon (red) and the overlay (blue).
    QRect redBox;
    QRect blueBox;
    for (int y = 0; y < result.height(); ++y) {
        for (int x = 0; x < result.width(); ++x) {
            const QRgb px = result.pixel(x, y);
            if (qBlue(px) == 255 && qRed(px) == 0) {
                blueBox = blueBox.isNull() ? QRect(x, y, 1, 1) : blueBox.united(QRect(x, y, 1, 1));
            } else if (qRed(px) == 255 && qBlue(px) == 0) {
                redBox = redBox.isNull() ? QRect(x, y, 1, 1) : redBox.united(QRect(x, y, 1, 1));
            }
        }
    }

    QVERIFY(!redBox.isNull());
    QVERIFY(!blueBox.isNull());

    // The base icon is narrower than the rect (tall aspect ratio, centered).
    QVERIFY(redBox.width() < result.width());

    // The bottom-right overlay must sit at the icon's corner, i.e. within the
    // icon's horizontal span, not detached towards an edge of the rect.
    QVERIFY(blueBox.left() >= redBox.left());
    QVERIFY(blueBox.right() <= redBox.right());
    QVERIFY(blueBox.bottom() <= redBox.bottom());
}

#include "moc_kiconutilstest.cpp"
