/*
    SPDX-FileCopyrightText: 2007 Albert Astals Cid <aacid@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "rendererthread.h"

#include <QImage>

#include "spectre_debug.h"

#include "core/generator.h"
#include "core/page.h"
#include "core/utils.h"

GSRendererThread *GSRendererThread::theRenderer = nullptr;

GSRendererThread *GSRendererThread::getCreateRenderer()
{
    if (!theRenderer) {
        theRenderer = new GSRendererThread();
    }
    return theRenderer;
}

GSRendererThread::GSRendererThread()
{
    m_renderContext = spectre_render_context_new();
}

GSRendererThread::~GSRendererThread()
{
    spectre_render_context_free(m_renderContext);
}

void GSRendererThread::addRequest(const GSRendererThreadRequest &req)
{
    m_queueMutex.lock();
    m_queue.enqueue(req);
    m_queueMutex.unlock();
    m_semaphore.release();
}

void GSRendererThread::run()
{
    while (true) {
        m_semaphore.acquire();
        {
            m_queueMutex.lock();
            GSRendererThreadRequest req = m_queue.dequeue();
            m_queueMutex.unlock();

            spectre_render_context_set_scale(m_renderContext, req.magnify, req.magnify);
            spectre_render_context_set_use_platform_fonts(m_renderContext, req.platformFonts);
            spectre_render_context_set_antialias_bits(m_renderContext, req.graphicsAAbits, req.textAAbits);
            // Do not use spectre_render_context_set_rotation makes some files not render correctly, e.g. bug210499.ps
            // so we basically do the rendering without any rotation and then rotate to the orientation as needed
            // spectre_render_context_set_rotation(m_renderContext, req.orientation);

            unsigned char *data = nullptr;
            int row_length = 0;
            int wantedWidth = req.request->width();
            int wantedHeight = req.request->height();

            if (req.orientation % 2) {
                std::swap(wantedWidth, wantedHeight);
            }

            spectre_page_render(req.spectrePage, m_renderContext, &data, &row_length);

            // Qt needs the missing alpha of QImage::Format_RGB32 to be 0xff
            if (data && data[3] != 0xff) {
                for (int i = 3; i < row_length * wantedHeight; i += 4) {
                    data[i] = 0xff;
                }
            }

            QImage img;
            if (row_length == wantedWidth * 4) {
                img = QImage(data, wantedWidth, wantedHeight, QImage::Format_RGB32);
            } else {
                // In case this ends up beign very slow we can try with some memmove
                QImage aux(data, row_length / 4, wantedHeight, QImage::Format_RGB32);
                img = QImage(aux.copy(0, 0, wantedWidth, wantedHeight));
            }

            switch (req.orientation) {
            case Okular::Rotation90: {
                QTransform m;
                m.rotate(90);
                img = img.transformed(m);
                break;
            }

            case Okular::Rotation180: {
                QTransform m;
                m.rotate(180);
                img = img.transformed(m);
                break;
            }
            case Okular::Rotation270: {
                QTransform m;
                m.rotate(270);
                img = img.transformed(m);
            }
            }

            QImage *image = new QImage(img.copy());
            free(data);

            if (image->width() != req.request->width() || image->height() != req.request->height()) {
                qCWarning(OkularSpectreDebug).nospace() << "Generated image does not match wanted size: "
                                                        << "[" << image->width() << "x" << image->height() << "] vs requested "
                                                        << "[" << req.request->width() << "x" << req.request->height() << "]";
                QImage aux = image->scaled(wantedWidth, wantedHeight);
                delete image;
                image = new QImage(aux);
            }
            Q_EMIT imageDone(image, req.request);

            spectre_page_free(req.spectrePage);
        }
    }
}

/* kate: replace-tabs on; indent-width 4; */
