<commit_before>#include "PublishSpriteSheet.h"
#include "SpritePackerProjectFile.h"
#include "SpriteAtlas.h"
#include "PListSerializer.h"
#include <QMessageBox>
#include "PngOptimizer.h"
#include "PVRTexture.h"
#include "PVRTextureUtilities.h"

using namespace pvrtexture;

QMap<QString, QString> PublishSpriteSheet::_formats;

QString imagePrefix(ImageFormat imageFormat) {
    switch (imageFormat) {
        case kPNG: return ".png";
        case kJPG: return ".jpg";
        case kPKM: return ".pvr";
        case kPVR: return ".pvr";
        case kPVR_CCZ: return ".pvr.ccz";
        default: return ".png";
    }
}

QJSValue jsValue(QJSEngine& engine, const QRect& rect) {
    QJSValue value = engine.newObject();
    value.setProperty("x", rect.left());
    value.setProperty("y", rect.top());
    value.setProperty("width", rect.width());
    value.setProperty("height", rect.height());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const QSize& size) {
    QJSValue value = engine.newObject();
    value.setProperty("width", size.width());
    value.setProperty("height", size.height());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const QPoint& point) {
    QJSValue value = engine.newObject();
    value.setProperty("x", point.x());
    value.setProperty("y", point.y());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const Triangles& triangles) {
    QJSValue value = engine.newObject();

    int index = 0;
    QJSValue verts = engine.newArray(triangles.verts.size());
    for (auto vert: triangles.verts) {
        verts.setProperty(index, jsValue(engine, vert));
        ++index;
    }
    value.setProperty("verts", verts);

    index = 0;
    QJSValue indices = engine.newArray(triangles.indices.size());
    for (auto idx: triangles.indices) {
        indices.setProperty(index, idx);
        ++index;
    }
    value.setProperty("indices", indices);
    return value;
}

void JSConsole::log(QString msg) {
    qDebug() << "js:"<< msg;
}

PublishSpriteSheet::PublishSpriteSheet() {
    _imageFormat = kPNG;
    _pixelFormat = kARGB8888;
    _premultiplied = true;
    _jpgQuality = 80;

    _trimSpriteNames = true;
    _prependSmartFolderName = true;
}

void PublishSpriteSheet::addSpriteSheet(const SpriteAtlas &atlas, const QString &fileName) {
    _spriteAtlases.append(atlas);
    _fileNames.append(fileName);
}

bool PublishSpriteSheet::publish(const QString& format, bool errorMessage) {

    if (_spriteAtlases.size() != _fileNames.size()) {
        return false;
    }

    QStringList outputFilePaths;
    for (int i = 0; i < _spriteAtlases.size(); i++) {
        const SpriteAtlas& atlas = _spriteAtlases.at(i);
        const QString& filePath = _fileNames.at(i);

        for (int n=0; n<atlas.outputData().size(); ++n) {
            const auto& outputData = atlas.outputData().at(n);

            QString outputFilePath = filePath;
            if (outputFilePath.contains("{n}")) {
                outputFilePath.replace("{n}", QString::number(n));
            } else if (outputFilePath.contains("{n1}")) {
                outputFilePath.replace("{n1}", QString::number(n + 1));
            } else if (atlas.outputData().size() > 1) {
                outputFilePath = outputFilePath + "_" + QString::number(n);
            }

            // save this name for optimize png
            outputFilePaths.push_back(outputFilePath);

            // generate the data file and the image
            if (!generateDataFile(outputFilePath, format, outputData._spriteFrames, outputData._atlasImage, errorMessage)) {
                return false;
            }

            // save image
            qDebug() << "Save image:" << outputFilePath + imagePrefix(_imageFormat);
            if ((_imageFormat == kPNG) || (_imageFormat == kJPG) || (_imageFormat == kJPG_PNG)) {
                QImage image = convertImage(outputData._atlasImage, _pixelFormat, _premultiplied);
                if (_imageFormat == kPNG) {
                    QImageWriter writer(outputFilePath + imagePrefix(kPNG), "png");
                    writer.setOptimizedWrite(true);
                    writer.setCompression(100);
                    writer.setQuality(0);
                    writer.write(image);
                } else if ((_imageFormat == kJPG) || (_imageFormat == kJPG_PNG)) {
                    QImageWriter writer(outputFilePath + imagePrefix(kJPG), "jpg");
                    writer.setOptimizedWrite(true);
                    writer.setCompression(100);
                    writer.setQuality(_jpgQuality);
                    writer.write(image);

                    if (_imageFormat == kJPG_PNG) {
                        QImage maskImage = convertImage(outputData._atlasImage, kALPHA, _premultiplied);
                        QImageWriter writer(outputFilePath + imagePrefix(kPNG), "png");
                        writer.setOptimizedWrite(true);
                        writer.setCompression(100);
                        writer.setQuality(0);
                        writer.write(maskImage);
                    }
                }
            } else if ((_imageFormat == kPKM) || (_imageFormat == kPVR) || (_imageFormat == kPVR_CCZ)) {
                CPVRTextureHeader pvrHeader(PVRStandard8PixelType.PixelTypeID, outputData._atlasImage.width(), outputData._atlasImage.height());

                // create the texture
                CPVRTexture pvrTexture(pvrHeader, outputData._atlasImage.bits());
                switch (_pixelFormat) {
                    case kETC1: Transcode(pvrTexture, ePVRTPF_ETC1, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC2: Transcode(pvrTexture, ePVRTPF_PVRTCI_2bpp_RGB, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC2A: Transcode(pvrTexture, ePVRTPF_PVRTCI_2bpp_RGBA, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC4: Transcode(pvrTexture, ePVRTPF_PVRTCI_4bpp_RGB, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC4A: Transcode(pvrTexture, ePVRTPF_PVRTCI_4bpp_RGBA, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    default: Transcode(pvrTexture, ePVRTPF_ETC1, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                }
                // save the file
                if (_imageFormat == kPVR_CCZ) {
                    //TODO: use qCompress
                } else {
                    pvrTexture.saveFile((outputFilePath + imagePrefix(_imageFormat)).toStdString().c_str());
                }
            }
        }
    }

    if ((_imageFormat == kPNG) && (_pngQuality.optMode != "None")) {
        qDebug() << "Begin optimize image...";
        // we use values 1-7 so that it is more user friendly, because 0 also means optimization.
        optimizePNGInThread(outputFilePaths, _pngQuality.optMode, _pngQuality.optLevel - 1);
    }

    _spriteAtlases.clear();
    _fileNames.clear();

    return true;
}

bool PublishSpriteSheet::generateDataFile(const QString& filePath, const QString& format,  const QMap<QString, SpriteFrameInfo>& spriteFrames, const QImage& atlasImage, bool errorMessage) {
    QJSEngine engine;

    auto it_format = _formats.find(format);
    if (it_format == _formats.end()) {
        QString errorString = QString("Not found script file for [%1] format").arg(format);
        qDebug() << errorString;
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
        return false;
    }

    QString scriptFileName = it_format.value();
    QFile scriptFile(scriptFileName);
    if (!scriptFile.open(QIODevice::ReadOnly)) {
        qDebug() << "File [" << scriptFileName << "] not found!";
        return false;
    }

    QTextStream stream(&scriptFile);
    QString contents = stream.readAll();
    scriptFile.close();

    // add console object
    JSConsole console;
    QJSValue consoleObj = engine.newQObject(&console);
    engine.globalObject().setProperty("console", consoleObj);

    // evaluate export plugin script
    qDebug() << "Run script...";
    QJSValue result = engine.evaluate(contents);
    if (result.isError()) {
        QString errorString = "Uncaught exception at line " + result.property("lineNumber").toString() + " : " + result.toString();
        qDebug() << errorString;
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
        return false;
    }

    if (engine.globalObject().hasOwnProperty("exportSpriteSheet")) {
        QJSValueList args;
        args << QJSValue(filePath);
        if (_imageFormat == kJPG_PNG) {
            QJSValue imageFilePathsValue = engine.newObject();
            imageFilePathsValue.setProperty("rgb", QJSValue(filePath + imagePrefix(kJPG)));
            imageFilePathsValue.setProperty("mask", QJSValue(filePath + imagePrefix(kPNG)));
            args << imageFilePathsValue;
        } else {
            args << QJSValue(filePath + imagePrefix(_imageFormat));
        }

        // collect sprite frames
        QJSValue spriteFramesValue = engine.newObject();
        auto it_f = spriteFrames.cbegin();
        for (; it_f != spriteFrames.cend(); ++it_f) {
            QJSValue spriteFrameValue = engine.newObject();
            spriteFrameValue.setProperty("frame", jsValue(engine, it_f.value().frame));
            spriteFrameValue.setProperty("offset", jsValue(engine, it_f.value().offset));
            spriteFrameValue.setProperty("rotated", it_f.value().rotated);
            spriteFrameValue.setProperty("sourceColorRect", jsValue(engine, it_f.value().sourceColorRect));
            spriteFrameValue.setProperty("sourceSize", jsValue(engine, it_f.value().sourceSize));
            spriteFrameValue.setProperty("triangles", jsValue(engine, it_f.value().triangles));

            QString name = it_f.key();
            // remove root folder if needed
            if (!_prependSmartFolderName) {
                auto idx = name.indexOf('/');
                if (idx != -1) {
                    name = name.right(name.length() - idx - 1);
                }
            }
            if (_trimSpriteNames) {
                name = QFileInfo(name).path() + QDir::separator() + QFileInfo(name).baseName();
            }
            spriteFramesValue.setProperty(name, spriteFrameValue);
        }
        args << QJSValue(spriteFramesValue);

        args << jsValue(engine, atlasImage.size());

        // run export
        QJSValue exportSpriteSheet = engine.globalObject().property("exportSpriteSheet");
        result = exportSpriteSheet.call(args);

        if (result.isError()) {
            QString errorString = "Uncaught exception at line " + result.property("lineNumber").toString() + " : " + result.toString();
            qDebug() << errorString;
            if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
            return false;
        } else {
            // write data
            if (!result.hasProperty("data") || !result.hasProperty("format")) {
                QString errorString = "Script function must be return object: {data:data, format:'plist|json|other'}";
                qDebug() << errorString;
                if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
                return false;
            } else {
                QJSValue data = result.property("data");
                QString format = result.property("format").toString();
                QFile file(filePath + "." + format);
                file.open(QIODevice::WriteOnly | QIODevice::Text);
                QTextStream out(&file);
                if (format == "plist") {
                    out << PListSerializer::toPList(data.toVariant());
                } else {
                    out << data.toString();
                }
            }
        }

    } else {
        qDebug() << "Not found global exportSpriteSheet function!";
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", "Not found global exportSpriteSheet function!");
        return false;
    }

    return true;
}

bool PublishSpriteSheet::optimizePNG(const QString& fileName, const QString& optMode, int optLevel) {
    bool result = false;

    if (optMode == "Lossless") {
        OptiPngOptimizer optimizer(optLevel);

        _mutex.lock();
        result = optimizer.optimizeFile(fileName + ".png");
        _mutex.unlock();
    } else if (optMode == "Lossy") {
        PngQuantOptimizer optimizer(optLevel);

        _mutex.lock();
        result = optimizer.optimizeFile(fileName + ".png");
        _mutex.unlock();
    }

    return result;
}

void PublishSpriteSheet::optimizePNGInThread(QStringList fileNames, const QString& optMode, int optLevel) {
    QObject::connect(&_watcher, SIGNAL(finished()), this, SIGNAL(onCompletedOptimizePNG()));

    QFuture<bool> resultFuture;

    for (const QString& fileName : fileNames) {
        resultFuture = QtConcurrent::run(this, &PublishSpriteSheet::optimizePNG, fileName, optMode, optLevel);
    }

    _watcher.setFuture(resultFuture);
}
<commit_msg>fix windows separator in spriteframe names<commit_after>#include "PublishSpriteSheet.h"
#include "SpritePackerProjectFile.h"
#include "SpriteAtlas.h"
#include "PListSerializer.h"
#include <QMessageBox>
#include "PngOptimizer.h"
#include "PVRTexture.h"
#include "PVRTextureUtilities.h"

using namespace pvrtexture;

QMap<QString, QString> PublishSpriteSheet::_formats;

QString imagePrefix(ImageFormat imageFormat) {
    switch (imageFormat) {
        case kPNG: return ".png";
        case kJPG: return ".jpg";
        case kPKM: return ".pvr";
        case kPVR: return ".pvr";
        case kPVR_CCZ: return ".pvr.ccz";
        default: return ".png";
    }
}

QJSValue jsValue(QJSEngine& engine, const QRect& rect) {
    QJSValue value = engine.newObject();
    value.setProperty("x", rect.left());
    value.setProperty("y", rect.top());
    value.setProperty("width", rect.width());
    value.setProperty("height", rect.height());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const QSize& size) {
    QJSValue value = engine.newObject();
    value.setProperty("width", size.width());
    value.setProperty("height", size.height());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const QPoint& point) {
    QJSValue value = engine.newObject();
    value.setProperty("x", point.x());
    value.setProperty("y", point.y());
    return value;
}

QJSValue jsValue(QJSEngine& engine, const Triangles& triangles) {
    QJSValue value = engine.newObject();

    int index = 0;
    QJSValue verts = engine.newArray(triangles.verts.size());
    for (auto vert: triangles.verts) {
        verts.setProperty(index, jsValue(engine, vert));
        ++index;
    }
    value.setProperty("verts", verts);

    index = 0;
    QJSValue indices = engine.newArray(triangles.indices.size());
    for (auto idx: triangles.indices) {
        indices.setProperty(index, idx);
        ++index;
    }
    value.setProperty("indices", indices);
    return value;
}

void JSConsole::log(QString msg) {
    qDebug() << "js:"<< msg;
}

PublishSpriteSheet::PublishSpriteSheet() {
    _imageFormat = kPNG;
    _pixelFormat = kARGB8888;
    _premultiplied = true;
    _jpgQuality = 80;

    _trimSpriteNames = true;
    _prependSmartFolderName = true;
}

void PublishSpriteSheet::addSpriteSheet(const SpriteAtlas &atlas, const QString &fileName) {
    _spriteAtlases.append(atlas);
    _fileNames.append(fileName);
}

bool PublishSpriteSheet::publish(const QString& format, bool errorMessage) {

    if (_spriteAtlases.size() != _fileNames.size()) {
        return false;
    }

    QStringList outputFilePaths;
    for (int i = 0; i < _spriteAtlases.size(); i++) {
        const SpriteAtlas& atlas = _spriteAtlases.at(i);
        const QString& filePath = _fileNames.at(i);

        for (int n=0; n<atlas.outputData().size(); ++n) {
            const auto& outputData = atlas.outputData().at(n);

            QString outputFilePath = filePath;
            if (outputFilePath.contains("{n}")) {
                outputFilePath.replace("{n}", QString::number(n));
            } else if (outputFilePath.contains("{n1}")) {
                outputFilePath.replace("{n1}", QString::number(n + 1));
            } else if (atlas.outputData().size() > 1) {
                outputFilePath = outputFilePath + "_" + QString::number(n);
            }

            // save this name for optimize png
            outputFilePaths.push_back(outputFilePath);

            // generate the data file and the image
            if (!generateDataFile(outputFilePath, format, outputData._spriteFrames, outputData._atlasImage, errorMessage)) {
                return false;
            }

            // save image
            qDebug() << "Save image:" << outputFilePath + imagePrefix(_imageFormat);
            if ((_imageFormat == kPNG) || (_imageFormat == kJPG) || (_imageFormat == kJPG_PNG)) {
                QImage image = convertImage(outputData._atlasImage, _pixelFormat, _premultiplied);
                if (_imageFormat == kPNG) {
                    QImageWriter writer(outputFilePath + imagePrefix(kPNG), "png");
                    writer.setOptimizedWrite(true);
                    writer.setCompression(100);
                    writer.setQuality(0);
                    writer.write(image);
                } else if ((_imageFormat == kJPG) || (_imageFormat == kJPG_PNG)) {
                    QImageWriter writer(outputFilePath + imagePrefix(kJPG), "jpg");
                    writer.setOptimizedWrite(true);
                    writer.setCompression(100);
                    writer.setQuality(_jpgQuality);
                    writer.write(image);

                    if (_imageFormat == kJPG_PNG) {
                        QImage maskImage = convertImage(outputData._atlasImage, kALPHA, _premultiplied);
                        QImageWriter writer(outputFilePath + imagePrefix(kPNG), "png");
                        writer.setOptimizedWrite(true);
                        writer.setCompression(100);
                        writer.setQuality(0);
                        writer.write(maskImage);
                    }
                }
            } else if ((_imageFormat == kPKM) || (_imageFormat == kPVR) || (_imageFormat == kPVR_CCZ)) {
                CPVRTextureHeader pvrHeader(PVRStandard8PixelType.PixelTypeID, outputData._atlasImage.width(), outputData._atlasImage.height());

                // create the texture
                CPVRTexture pvrTexture(pvrHeader, outputData._atlasImage.bits());
                switch (_pixelFormat) {
                    case kETC1: Transcode(pvrTexture, ePVRTPF_ETC1, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC2: Transcode(pvrTexture, ePVRTPF_PVRTCI_2bpp_RGB, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC2A: Transcode(pvrTexture, ePVRTPF_PVRTCI_2bpp_RGBA, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC4: Transcode(pvrTexture, ePVRTPF_PVRTCI_4bpp_RGB, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    case kPVRTC4A: Transcode(pvrTexture, ePVRTPF_PVRTCI_4bpp_RGBA, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                    default: Transcode(pvrTexture, ePVRTPF_ETC1, ePVRTVarTypeUnsignedByteNorm, ePVRTCSpacelRGB); break;
                }
                // save the file
                if (_imageFormat == kPVR_CCZ) {
                    //TODO: use qCompress
                } else {
                    pvrTexture.saveFile((outputFilePath + imagePrefix(_imageFormat)).toStdString().c_str());
                }
            }
        }
    }

    if ((_imageFormat == kPNG) && (_pngQuality.optMode != "None")) {
        qDebug() << "Begin optimize image...";
        // we use values 1-7 so that it is more user friendly, because 0 also means optimization.
        optimizePNGInThread(outputFilePaths, _pngQuality.optMode, _pngQuality.optLevel - 1);
    }

    _spriteAtlases.clear();
    _fileNames.clear();

    return true;
}

bool PublishSpriteSheet::generateDataFile(const QString& filePath, const QString& format,  const QMap<QString, SpriteFrameInfo>& spriteFrames, const QImage& atlasImage, bool errorMessage) {
    QJSEngine engine;

    auto it_format = _formats.find(format);
    if (it_format == _formats.end()) {
        QString errorString = QString("Not found script file for [%1] format").arg(format);
        qDebug() << errorString;
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
        return false;
    }

    QString scriptFileName = it_format.value();
    QFile scriptFile(scriptFileName);
    if (!scriptFile.open(QIODevice::ReadOnly)) {
        qDebug() << "File [" << scriptFileName << "] not found!";
        return false;
    }

    QTextStream stream(&scriptFile);
    QString contents = stream.readAll();
    scriptFile.close();

    // add console object
    JSConsole console;
    QJSValue consoleObj = engine.newQObject(&console);
    engine.globalObject().setProperty("console", consoleObj);

    // evaluate export plugin script
    qDebug() << "Run script...";
    QJSValue result = engine.evaluate(contents);
    if (result.isError()) {
        QString errorString = "Uncaught exception at line " + result.property("lineNumber").toString() + " : " + result.toString();
        qDebug() << errorString;
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
        return false;
    }

    if (engine.globalObject().hasOwnProperty("exportSpriteSheet")) {
        QJSValueList args;
        args << QJSValue(filePath);
        if (_imageFormat == kJPG_PNG) {
            QJSValue imageFilePathsValue = engine.newObject();
            imageFilePathsValue.setProperty("rgb", QJSValue(filePath + imagePrefix(kJPG)));
            imageFilePathsValue.setProperty("mask", QJSValue(filePath + imagePrefix(kPNG)));
            args << imageFilePathsValue;
        } else {
            args << QJSValue(filePath + imagePrefix(_imageFormat));
        }

        // collect sprite frames
        QJSValue spriteFramesValue = engine.newObject();
        auto it_f = spriteFrames.cbegin();
        for (; it_f != spriteFrames.cend(); ++it_f) {
            QJSValue spriteFrameValue = engine.newObject();
            spriteFrameValue.setProperty("frame", jsValue(engine, it_f.value().frame));
            spriteFrameValue.setProperty("offset", jsValue(engine, it_f.value().offset));
            spriteFrameValue.setProperty("rotated", it_f.value().rotated);
            spriteFrameValue.setProperty("sourceColorRect", jsValue(engine, it_f.value().sourceColorRect));
            spriteFrameValue.setProperty("sourceSize", jsValue(engine, it_f.value().sourceSize));
            spriteFrameValue.setProperty("triangles", jsValue(engine, it_f.value().triangles));

            QString name = it_f.key();
            // remove root folder if needed
            if (!_prependSmartFolderName) {
                auto idx = name.indexOf('/');
                if (idx != -1) {
                    name = name.right(name.length() - idx - 1);
                }
            }
            if (_trimSpriteNames) {
                name = QDir::fromNativeSeparators(QFileInfo(name).path() + QDir::separator() + QFileInfo(name).baseName());
            }
            spriteFramesValue.setProperty(name, spriteFrameValue);
        }
        args << QJSValue(spriteFramesValue);

        args << jsValue(engine, atlasImage.size());

        // run export
        QJSValue exportSpriteSheet = engine.globalObject().property("exportSpriteSheet");
        result = exportSpriteSheet.call(args);

        if (result.isError()) {
            QString errorString = "Uncaught exception at line " + result.property("lineNumber").toString() + " : " + result.toString();
            qDebug() << errorString;
            if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
            return false;
        } else {
            // write data
            if (!result.hasProperty("data") || !result.hasProperty("format")) {
                QString errorString = "Script function must be return object: {data:data, format:'plist|json|other'}";
                qDebug() << errorString;
                if (errorMessage) QMessageBox::critical(NULL, "Export script error", errorString);
                return false;
            } else {
                QJSValue data = result.property("data");
                QString format = result.property("format").toString();
                QFile file(filePath + "." + format);
                file.open(QIODevice::WriteOnly | QIODevice::Text);
                QTextStream out(&file);
                if (format == "plist") {
                    out << PListSerializer::toPList(data.toVariant());
                } else {
                    out << data.toString();
                }
            }
        }

    } else {
        qDebug() << "Not found global exportSpriteSheet function!";
        if (errorMessage) QMessageBox::critical(NULL, "Export script error", "Not found global exportSpriteSheet function!");
        return false;
    }

    return true;
}

bool PublishSpriteSheet::optimizePNG(const QString& fileName, const QString& optMode, int optLevel) {
    bool result = false;

    if (optMode == "Lossless") {
        OptiPngOptimizer optimizer(optLevel);

        _mutex.lock();
        result = optimizer.optimizeFile(fileName + ".png");
        _mutex.unlock();
    } else if (optMode == "Lossy") {
        PngQuantOptimizer optimizer(optLevel);

        _mutex.lock();
        result = optimizer.optimizeFile(fileName + ".png");
        _mutex.unlock();
    }

    return result;
}

void PublishSpriteSheet::optimizePNGInThread(QStringList fileNames, const QString& optMode, int optLevel) {
    QObject::connect(&_watcher, SIGNAL(finished()), this, SIGNAL(onCompletedOptimizePNG()));

    QFuture<bool> resultFuture;

    for (const QString& fileName : fileNames) {
        resultFuture = QtConcurrent::run(this, &PublishSpriteSheet::optimizePNG, fileName, optMode, optLevel);
    }

    _watcher.setFuture(resultFuture);
}
<|endoftext|>


<commit_before>// Copyright 2022 The gRPC Authors
//
// 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 <grpc/support/port_platform.h>

#include <deque>

#include "absl/container/flat_hash_map.h"

#include "src/core/lib/event_engine/common_closures.h"
#include "src/core/lib/event_engine/work_queue.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/event_engine/work_queue/work_queue_fuzzer.pb.h"

bool squelch = true;
bool leak_check = true;

namespace grpc_event_engine {
namespace experimental {

class WorkQueueFuzzer {
 public:
  WorkQueueFuzzer() { CheckEqual(); };
  ~WorkQueueFuzzer() { CheckEqual(); };

  void Run(const work_queue_fuzzer::Action& action) {
    switch (action.action_type_case()) {
      case work_queue_fuzzer::Action::kAdd: {
        if (action.add().type() == work_queue_fuzzer::CALLBACK_TYPE_CLOSURE) {
          work_queue_.Add(CreateClosure(action.add().key()));
          deque_.push_back(CreateClosure(action.add().key()));
        } else {
          work_queue_.Add(CreateInvocable(action.add().key()));
          deque_.push_back(CreateClosureWrappedInvocable(action.add().key()));
        }
      } break;
      case work_queue_fuzzer::Action::kPopFront: {
        // pop front closures, executing both to check they are a pair
        auto* wq_c = work_queue_.PopFront();
        if (wq_c == nullptr) {
          if (!work_queue_.Empty() || !deque_.empty()) abort();
        } else {
          auto* dq_c = deque_.front();
          deque_.pop_front();
          wq_c->Run();
          dq_c->Run();
        }
      } break;
      case work_queue_fuzzer::Action::kPopBack: {
        // pop back closures, executing both to check they are a pair
        auto* wq_c = work_queue_.PopBack();
        if (wq_c == nullptr) {
          if (!work_queue_.Empty() || !deque_.empty()) abort();
        } else {
          auto* dq_c = deque_.back();
          deque_.pop_back();
          wq_c->Run();
          dq_c->Run();
        }
      } break;
      case work_queue_fuzzer::Action::kEmpty: {
        if (work_queue_.Empty() != deque_.empty()) abort();
      } break;
      case work_queue_fuzzer::Action::ACTION_TYPE_NOT_SET:
        break;
    };
  }

 private:
  EventEngine::Closure* CreateClosure(int key) {
    return SelfDeletingClosure::Create([key, this] {
      if (last_executed_key_.has_value()) {
        if (*last_executed_key_ != key) abort();
        last_executed_key_.reset();
      } else {
        last_executed_key_ = key;
      }
    });
  }

  absl::AnyInvocable<void()> CreateInvocable(int key) {
    return absl::AnyInvocable<void()>([key, this] {
      if (last_executed_key_.has_value()) {
        if (*last_executed_key_ != key) abort();
        last_executed_key_.reset();
      } else {
        last_executed_key_ = key;
      }
    });
  }

  EventEngine::Closure* CreateClosureWrappedInvocable(int key) {
    auto invocable = CreateInvocable(key);
    return SelfDeletingClosure::Create(
        [invocable = std::move(invocable)]() mutable { invocable(); });
  }

  void CheckEqual() {
    while (auto* wq_c = work_queue_.PopBack()) {
      if (deque_.empty()) abort();
      auto* dq_c = deque_.back();
      deque_.pop_back();
      wq_c->Run();
      dq_c->Run();
    }
  }

  WorkQueue work_queue_;
  std::deque<EventEngine::Closure*> deque_;
  // Closures are always added in pairs and checked in paris.
  // When checking, each popped closure encounters one of these situations:
  //  A) it is the first of a pair, denoted by an empty last_executed_key_, so
  //     it sets last_executed_key_ to its own key.
  //  B) last_executed_key_ is set, so its value must match this closure's own
  //     key to assert that it is the other part of the pair. last_executed_key_
  //     is then reset.
  absl::optional<int> last_executed_key_;
};

}  // namespace experimental
}  // namespace grpc_event_engine

DEFINE_PROTO_FUZZER(const work_queue_fuzzer::Msg& msg) {
  for (const auto& action : msg.actions()) {
    grpc_event_engine::experimental::WorkQueueFuzzer().Run(action);
  }
}
<commit_msg>small test cleanup (#31137)<commit_after>// Copyright 2022 The gRPC Authors
//
// 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 <grpc/support/port_platform.h>

#include <deque>

#include "absl/container/flat_hash_map.h"

#include "src/core/lib/event_engine/common_closures.h"
#include "src/core/lib/event_engine/work_queue.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/event_engine/work_queue/work_queue_fuzzer.pb.h"

bool squelch = true;
bool leak_check = true;

namespace grpc_event_engine {
namespace experimental {

class WorkQueueFuzzer {
 public:
  WorkQueueFuzzer() { CheckEqual(); }
  ~WorkQueueFuzzer() { CheckEqual(); }

  void Run(const work_queue_fuzzer::Action& action) {
    switch (action.action_type_case()) {
      case work_queue_fuzzer::Action::kAdd: {
        if (action.add().type() == work_queue_fuzzer::CALLBACK_TYPE_CLOSURE) {
          work_queue_.Add(CreateClosure(action.add().key()));
          deque_.push_back(CreateClosure(action.add().key()));
        } else {
          work_queue_.Add(CreateInvocable(action.add().key()));
          deque_.push_back(CreateClosureWrappedInvocable(action.add().key()));
        }
      } break;
      case work_queue_fuzzer::Action::kPopFront: {
        // pop front closures, executing both to check they are a pair
        auto* wq_c = work_queue_.PopFront();
        if (wq_c == nullptr) {
          if (!work_queue_.Empty() || !deque_.empty()) abort();
        } else {
          auto* dq_c = deque_.front();
          deque_.pop_front();
          wq_c->Run();
          dq_c->Run();
        }
      } break;
      case work_queue_fuzzer::Action::kPopBack: {
        // pop back closures, executing both to check they are a pair
        auto* wq_c = work_queue_.PopBack();
        if (wq_c == nullptr) {
          if (!work_queue_.Empty() || !deque_.empty()) abort();
        } else {
          auto* dq_c = deque_.back();
          deque_.pop_back();
          wq_c->Run();
          dq_c->Run();
        }
      } break;
      case work_queue_fuzzer::Action::kEmpty: {
        if (work_queue_.Empty() != deque_.empty()) abort();
      } break;
      case work_queue_fuzzer::Action::ACTION_TYPE_NOT_SET:
        break;
    }
  }

 private:
  EventEngine::Closure* CreateClosure(int key) {
    return SelfDeletingClosure::Create([key, this] {
      if (last_executed_key_.has_value()) {
        if (*last_executed_key_ != key) abort();
        last_executed_key_.reset();
      } else {
        last_executed_key_ = key;
      }
    });
  }

  absl::AnyInvocable<void()> CreateInvocable(int key) {
    return absl::AnyInvocable<void()>([key, this] {
      if (last_executed_key_.has_value()) {
        if (*last_executed_key_ != key) abort();
        last_executed_key_.reset();
      } else {
        last_executed_key_ = key;
      }
    });
  }

  EventEngine::Closure* CreateClosureWrappedInvocable(int key) {
    auto invocable = CreateInvocable(key);
    return SelfDeletingClosure::Create(
        [invocable = std::move(invocable)]() mutable { invocable(); });
  }

  void CheckEqual() {
    while (auto* wq_c = work_queue_.PopBack()) {
      if (deque_.empty()) abort();
      auto* dq_c = deque_.back();
      deque_.pop_back();
      wq_c->Run();
      dq_c->Run();
    }
  }

  WorkQueue work_queue_;
  std::deque<EventEngine::Closure*> deque_;
  // Closures are always added in pairs and checked in paris.
  // When checking, each popped closure encounters one of these situations:
  //  A) it is the first of a pair, denoted by an empty last_executed_key_, so
  //     it sets last_executed_key_ to its own key.
  //  B) last_executed_key_ is set, so its value must match this closure's own
  //     key to assert that it is the other part of the pair. last_executed_key_
  //     is then reset.
  absl::optional<int> last_executed_key_;
};

}  // namespace experimental
}  // namespace grpc_event_engine

DEFINE_PROTO_FUZZER(const work_queue_fuzzer::Msg& msg) {
  for (const auto& action : msg.actions()) {
    grpc_event_engine::experimental::WorkQueueFuzzer().Run(action);
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: basedlgs.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2007-04-11 21:16:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _BASEDLGS_HXX
#define _BASEDLGS_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef INCLUDED_SFX2_DLLAPI_H
#include "sfx2/dllapi.h"
#endif

#ifndef _SAL_TYPES_H_
#include "sal/types.h"
#endif
#ifndef _FLOATWIN_HXX //autogen
#include <vcl/floatwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _DIALOG_HXX //autogen
#include <vcl/dialog.hxx>
#endif

class SfxTabPage;
class SfxBindings;
class SfxChildWindow;
struct SfxChildWinInfo;
class SfxItemSet;
class SfxItemPool;
class OKButton;
class CancelButton;
class HelpButton;
class Button;

// class SfxModalDefParentHelper -----------------------------------------

class SfxModalDefParentHelper
{
private:
    Window *pOld;

public:
    SfxModalDefParentHelper(Window* pWindow);
    ~SfxModalDefParentHelper();
};

// class SfxModalDialog --------------------------------------------------

class SFX2_DLLPUBLIC SfxModalDialog: public ModalDialog
{
    sal_uInt32          nUniqId;
    String              aExtraData;
    Timer               aTimer;

    SAL_DLLPRIVATE SfxModalDialog(SfxModalDialog &); // not defined
    SAL_DLLPRIVATE void operator =(SfxModalDialog &); // not defined

//#if 0 // _SOLAR__PRIVATE
    DECL_DLLPRIVATE_LINK( TimerHdl_Impl, Timer* );
//#endif

    SAL_DLLPRIVATE void SetDialogData_Impl();
    SAL_DLLPRIVATE void GetDialogData_Impl();
    SAL_DLLPRIVATE void init();

protected:
    SfxModalDialog(Window *pParent, const ResId &);
    SfxModalDialog(Window* pParent, sal_uInt32 nUniqueId,
                   WinBits nWinStyle = WB_STDMODAL);
    ~SfxModalDialog();

    String&     GetExtraData()      { return aExtraData; }
    sal_uInt32  GetUniqId() const   { return nUniqId; }
};

// class SfxModelessDialog --------------------------------------------------
class SfxModelessDialog_Impl;
class SFX2_DLLPUBLIC SfxModelessDialog: public ModelessDialog
{
    SfxBindings*            pBindings;
    Size                    aSize;
    SfxModelessDialog_Impl* pImp;

    SAL_DLLPRIVATE SfxModelessDialog(SfxModelessDialog &); // not defined
    SAL_DLLPRIVATE void operator =(SfxModelessDialog &); // not defined

protected:
                            SfxModelessDialog( SfxBindings*, SfxChildWindow*,
                                Window*, const ResId& );
                            SfxModelessDialog( SfxBindings*, SfxChildWindow*,
                                Window*, WinBits nWinStyle = WB_STDMODELESS );
                            ~SfxModelessDialog();
    virtual BOOL            Close();
    virtual void            Resize();
    virtual void            Move();
    virtual void            StateChanged( StateChangedType nStateChange );

public:
    virtual void            FillInfo(SfxChildWinInfo&) const;
    void                    Initialize (SfxChildWinInfo* pInfo);
    virtual long            Notify( NotifyEvent& rNEvt );
    SfxBindings&            GetBindings()
                            { return *pBindings; }
};

// class SfxFloatingWindow --------------------------------------------------
class SfxFloatingWindow_Impl;
class SFX2_DLLPUBLIC SfxFloatingWindow: public FloatingWindow
{
    SfxBindings*            pBindings;
    Size                    aSize;
    SfxFloatingWindow_Impl* pImp;

    SAL_DLLPRIVATE SfxFloatingWindow(SfxFloatingWindow &); // not defined
    SAL_DLLPRIVATE void operator =(SfxFloatingWindow &); // not defined

protected:
                            SfxFloatingWindow( SfxBindings *pBindings,
                                              SfxChildWindow *pCW,
                                              Window* pParent,
                                              WinBits nWinBits=WB_STDMODELESS);
                            SfxFloatingWindow( SfxBindings *pBindings,
                                              SfxChildWindow *pCW,
                                              Window* pParent,
                                              const ResId& rResId);
                            ~SfxFloatingWindow();

    virtual void            StateChanged( StateChangedType nStateChange );
    virtual BOOL            Close();
    virtual void            Resize();
    virtual void            Move();
    virtual long            Notify( NotifyEvent& rNEvt );
    SfxBindings&            GetBindings()
                            { return *pBindings; }

public:
    virtual void            FillInfo(SfxChildWinInfo&) const;
    void                    Initialize (SfxChildWinInfo* pInfo);
};

// class SfxSingleTabDialog --------------------------------------------------

typedef USHORT* (*GetTabPageRanges)(); // liefert internationale Which-Werte

class SFX2_DLLPUBLIC SfxSingleTabDialog : public SfxModalDialog
{
public:
    SfxSingleTabDialog( Window* pParent, const SfxItemSet& rOptionsSet, USHORT nUniqueId );
    SfxSingleTabDialog( Window* pParent, USHORT nUniqueId, const SfxItemSet* pInSet = 0 );

    virtual             ~SfxSingleTabDialog();

    void                SetTabPage( SfxTabPage* pTabPage,
                                    GetTabPageRanges pRangesFunc = 0 );
    SfxTabPage*         GetTabPage() const { return pPage; }

        // liefert ggf. per Map konvertierte lokale Slots
    const USHORT*       GetInputRanges( const SfxItemPool& rPool );
    void                SetInputSet( const SfxItemSet* pInSet )
                            { pOptions = pInSet; }
    const SfxItemSet*   GetOutputItemSet() const { return pOutSet; }
    OKButton*           GetOKButton() const { return pOKBtn; }
    CancelButton*       GetCancelButton() const { return pCancelBtn; }

private:
    GetTabPageRanges    fnGetRanges;    // Pointer auf die Ranges-Funktion
    USHORT*             pRanges;

    OKButton*           pOKBtn;
    CancelButton*       pCancelBtn;
    HelpButton*         pHelpBtn;

    SfxTabPage*         pPage;
    const SfxItemSet*   pOptions;
    SfxItemSet*         pOutSet;

//#if 0 // _SOLAR__PRIVATE
    DECL_DLLPRIVATE_LINK( OKHdl_Impl, Button * );
//#endif
};

#endif

<commit_msg>INTEGRATION: CWS fwk82_SRC680 (1.2.208); FILE MERGED 2008/01/07 14:57:58 cd 1.2.208.1: #i63848# Include modeless dialog class and resize operation into the asynchronous processing of window attribute persistence (Views.xcu)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: basedlgs.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2008-01-29 16:27:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _BASEDLGS_HXX
#define _BASEDLGS_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef INCLUDED_SFX2_DLLAPI_H
#include "sfx2/dllapi.h"
#endif

#ifndef _SAL_TYPES_H_
#include "sal/types.h"
#endif
#ifndef _FLOATWIN_HXX //autogen
#include <vcl/floatwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _DIALOG_HXX //autogen
#include <vcl/dialog.hxx>
#endif

class SfxTabPage;
class SfxBindings;
class SfxChildWindow;
struct SfxChildWinInfo;
class SfxItemSet;
class SfxItemPool;
class OKButton;
class CancelButton;
class HelpButton;
class Button;

// class SfxModalDefParentHelper -----------------------------------------

class SfxModalDefParentHelper
{
private:
    Window *pOld;

public:
    SfxModalDefParentHelper(Window* pWindow);
    ~SfxModalDefParentHelper();
};

// class SfxModalDialog --------------------------------------------------

class SFX2_DLLPUBLIC SfxModalDialog: public ModalDialog
{
    sal_uInt32          nUniqId;
    String              aExtraData;
    Timer               aTimer;

    SAL_DLLPRIVATE SfxModalDialog(SfxModalDialog &); // not defined
    SAL_DLLPRIVATE void operator =(SfxModalDialog &); // not defined

//#if 0 // _SOLAR__PRIVATE
    DECL_DLLPRIVATE_LINK( TimerHdl_Impl, Timer* );
//#endif

    SAL_DLLPRIVATE void SetDialogData_Impl();
    SAL_DLLPRIVATE void GetDialogData_Impl();
    SAL_DLLPRIVATE void init();

protected:
    SfxModalDialog(Window *pParent, const ResId &);
    SfxModalDialog(Window* pParent, sal_uInt32 nUniqueId,
                   WinBits nWinStyle = WB_STDMODAL);
    ~SfxModalDialog();

    String&     GetExtraData()      { return aExtraData; }
    sal_uInt32  GetUniqId() const   { return nUniqId; }
};

// class SfxModelessDialog --------------------------------------------------
class SfxModelessDialog_Impl;
class SFX2_DLLPUBLIC SfxModelessDialog: public ModelessDialog
{
    SfxBindings*            pBindings;
    Size                    aSize;
    SfxModelessDialog_Impl* pImp;

    SAL_DLLPRIVATE SfxModelessDialog(SfxModelessDialog &); // not defined
    SAL_DLLPRIVATE void operator =(SfxModelessDialog &); // not defined

protected:
                            SfxModelessDialog( SfxBindings*, SfxChildWindow*,
                                Window*, const ResId& );
                            SfxModelessDialog( SfxBindings*, SfxChildWindow*,
                                Window*, WinBits nWinStyle = WB_STDMODELESS );
                            ~SfxModelessDialog();
    virtual BOOL            Close();
    virtual void            Resize();
    virtual void            Move();
    virtual void            StateChanged( StateChangedType nStateChange );

public:
    virtual void            FillInfo(SfxChildWinInfo&) const;
    void                    Initialize (SfxChildWinInfo* pInfo);
    virtual long            Notify( NotifyEvent& rNEvt );
    SfxBindings&            GetBindings()
                            { return *pBindings; }

    DECL_LINK( TimerHdl, Timer* );

};

// class SfxFloatingWindow --------------------------------------------------
class SfxFloatingWindow_Impl;
class SFX2_DLLPUBLIC SfxFloatingWindow: public FloatingWindow
{
    SfxBindings*            pBindings;
    Size                    aSize;
    SfxFloatingWindow_Impl* pImp;

    SAL_DLLPRIVATE SfxFloatingWindow(SfxFloatingWindow &); // not defined
    SAL_DLLPRIVATE void operator =(SfxFloatingWindow &); // not defined

protected:
                            SfxFloatingWindow( SfxBindings *pBindings,
                                              SfxChildWindow *pCW,
                                              Window* pParent,
                                              WinBits nWinBits=WB_STDMODELESS);
                            SfxFloatingWindow( SfxBindings *pBindings,
                                              SfxChildWindow *pCW,
                                              Window* pParent,
                                              const ResId& rResId);
                            ~SfxFloatingWindow();

    virtual void            StateChanged( StateChangedType nStateChange );
    virtual BOOL            Close();
    virtual void            Resize();
    virtual void            Move();
    virtual long            Notify( NotifyEvent& rNEvt );
    SfxBindings&            GetBindings()
                            { return *pBindings; }

public:
    virtual void            FillInfo(SfxChildWinInfo&) const;
    void                    Initialize (SfxChildWinInfo* pInfo);

    DECL_LINK( TimerHdl, Timer* );

};

// class SfxSingleTabDialog --------------------------------------------------

typedef USHORT* (*GetTabPageRanges)(); // liefert internationale Which-Werte

class SFX2_DLLPUBLIC SfxSingleTabDialog : public SfxModalDialog
{
public:
    SfxSingleTabDialog( Window* pParent, const SfxItemSet& rOptionsSet, USHORT nUniqueId );
    SfxSingleTabDialog( Window* pParent, USHORT nUniqueId, const SfxItemSet* pInSet = 0 );

    virtual             ~SfxSingleTabDialog();

    void                SetTabPage( SfxTabPage* pTabPage,
                                    GetTabPageRanges pRangesFunc = 0 );
    SfxTabPage*         GetTabPage() const { return pPage; }

        // liefert ggf. per Map konvertierte lokale Slots
    const USHORT*       GetInputRanges( const SfxItemPool& rPool );
    void                SetInputSet( const SfxItemSet* pInSet )
                            { pOptions = pInSet; }
    const SfxItemSet*   GetOutputItemSet() const { return pOutSet; }
    OKButton*           GetOKButton() const { return pOKBtn; }
    CancelButton*       GetCancelButton() const { return pCancelBtn; }

private:
    GetTabPageRanges    fnGetRanges;    // Pointer auf die Ranges-Funktion
    USHORT*             pRanges;

    OKButton*           pOKBtn;
    CancelButton*       pCancelBtn;
    HelpButton*         pHelpBtn;

    SfxTabPage*         pPage;
    const SfxItemSet*   pOptions;
    SfxItemSet*         pOutSet;

//#if 0 // _SOLAR__PRIVATE
    DECL_DLLPRIVATE_LINK( OKHdl_Impl, Button * );
//#endif
};

#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <unordered_map>
#include <cstring>
#include <limits>
#include <cmath>
#include <cfloat>

class Tokenizer {
public:
    void updateToken(
            const char *&text) //Указатель будет сдвигаться. Текст - это ссылка на указатель константной char. Не смогу менять то, что внутри, но указатель смогу.
    {
        while (const auto c = *text++) {//Когда встретит 0 - остановится. Приоритет выше у инкремента - прибавим сначала, но разыменуем предыдущий указатель
            switch (c) {
                case ' ':
                    continue;
                case '-':
                    thisToken = Token::Minus;
                    return;
                case '+':
                    thisToken = Token::Plus;
                    return;
                case '*':
                    thisToken = Token::Mul;
                    return;
                case '/':
                    thisToken = Token::Div;
                    return;
                case '(':
                    thisToken = Token::LBrace;
                    return;
                case ')':
                    thisToken = Token::RBrace;
                    return;
            }
            if (c >= '0' && c <= '9') {
                thisToken = Token::Number;
                return;
            }
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
                thisToken = Token::Const;
                return;
            }
            throw std::runtime_error("Invalid Symbol"); // Вместо return Token::Invalid;
        }
        thisToken = Token::End;
        return;
    }

    enum class Token {
        Minus,
        Plus,
        Mul,
        Div,
        Number,
        End,
        Const,
        LBrace,
        RBrace
    };

    Token thisToken;
};

template <class T>
struct Parser
{
};
template <class T>
struct NumericTraits
{
};

template<> struct NumericTraits<double>{
    static constexpr double min = std::numeric_limits<double>::min();
    static constexpr double max = std::numeric_limits<double>::max();
};

template <>
struct NumericTraits<int>{
    static constexpr int min = std::numeric_limits<int>::min();
    static constexpr int max = std::numeric_limits<int>::max();
};

template <>
struct NumericTraits<long>{
    static constexpr long min = std::numeric_limits<long>::min();
    static constexpr long max = std::numeric_limits<long>::max();
};

template<>
struct Parser<int>
{
  static bool parse(const char*& text, int& value)
  {
  	long tmp = long(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + long(*text - '0');
        }
  if(tmp < NumericTraits<int>::min || tmp > NumericTraits<int>::max)
  	return false;
  value = tmp;
  return true;
  }
  static long bigType;
  static bool checkType(long &a){
  	if(a > NumericTraits<int>::max || a < - NumericTraits<int>::max){
  		return false;
  	}
  	return true;
  }
};

template<>
struct Parser<long>
{
  static bool parse(const char*& text, long& value)
  {
  	long long tmp = (long long)(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + (long long)(*text - '0');
        }
  if(tmp < NumericTraits<long>::min || tmp > NumericTraits<long>::max)
  	return false;
  value = tmp;
  return true;
  }
  static long long bigType;
  static bool checkType(long long &a){
  	if(a > NumericTraits<long>::max || a < - NumericTraits<long>::max){
  		return false;
  	}
  	return true;
  }
};

template<>
struct Parser<double>
{
  static bool parse(const char*& text, double& value)
  {
  	long double tmp = (long double)(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + (long double)(*text - '0');
        }
        if((*text == '.') && (*(++text) >= '0' || *(text) <= '9')){
        	tmp += (long double)(*text - '0') / 10;
        	int power = -1;
        	while (*(++text) >= '0' && *text <= '9') {
        		--power;
            	tmp +=  (long double)(*text - '0') * pow(10.0, power);
        	}
    	}
  	if(!std::isfinite(tmp)){//Требуется, потому что в случае проверки NumericTraits 0.0 не пройдет проверку.
  		return false;
  	}
  	if(tmp > NumericTraits<double>::max){
  		return false;
  	}
  	value = tmp;
  	return true;
  }

  static bool checkType(long double &a){
  	if(!std::isfinite((double)a)){//Требуется, потому что в случае проверки NumericTraits 0.0 не пройдет проверку.
  		return false;
  	}
  	if(a > NumericTraits<double>::max || a < - NumericTraits<double>::max){
  		return false;
  	}
  	return true;
  }
  static long double bigType;
};

template <class T, class Parser>
class calculator {
public:
    calculator(char *&text){
        expression = text;
    }
    calculator(){

    }

    T calculate(char *&text){
    	expression = text;
    	T result = expr(expression);
        std::cout << result << std::endl;
        return result;
    }

    /*void setExpr(std::string expr){
    	//this->expression = expr;
    	strcpy(this->expression, expr.c_str());
    }*/

private:
    T prim(const char *&text) {
        bool isPositive = true;
        thisToken.updateToken(text);
        --text;
        if (thisToken.thisToken == Tokenizer::Token::Minus) { //Checking if number is positive/negative
            isPositive = false;
            thisToken.updateToken(++text); //Checking what goes after subtraction symbol
            --text;
        }
        if(thisToken.thisToken == Tokenizer::Token::LBrace){//If there are braces - create loop to calculate expr in braces.
            ++text;
            T c = expr(text, true);
            return c * (2 * isPositive - 1);
        }
        if (thisToken.thisToken == Tokenizer::Token::End) {
            return 0;
        }
        if (thisToken.thisToken == Tokenizer::Token::Const){
            int length = 1;
            ++text ;
            while ((*text >= 'A' && *text <= 'Z') || (*text >= 'a' && *text <= 'z')) {
                length += 1;
                ++text;
            }
            std::string var;
            //auto* var = new std::string();
            var.assign(text-length, length);
            return constants.at(var) * (2 * isPositive - 1);
        }
        if (thisToken.thisToken != Tokenizer::Token::Number) {
            throw std::runtime_error("Syntax error");
        }
        T c;
        if(!Parser::parse(text, c))
    		throw std::runtime_error ("Syntax error: number can not be read");

        return c * (2 * isPositive - 1);

    }

    T term(const char *&text) {
        T c = prim(text);
        thisToken.updateToken(text);
        while (thisToken.thisToken == Tokenizer::Token::Mul || thisToken.thisToken == Tokenizer::Token::Div) {

            decltype(Parser::bigType) test = 0.0;
            if (thisToken.thisToken == Tokenizer::Token::Mul) {

            	test = (decltype(Parser::bigType))c * (decltype(Parser::bigType))prim(text);
            	if(Parser::checkType(test)){
            		c = T(test);
            	}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else {
                T divider = prim(text);
                if (divider) {

                	test = (decltype(Parser::bigType))c / (decltype(Parser::bigType))divider;
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                    thisToken.updateToken(text);
                } else throw std::runtime_error("Division by zero");
            }
        }
        --text;
        return c;
    }

    T expr(const char *&text, bool fromPrim = false) {
        T c = term(text);
        thisToken.updateToken(text);
        while (thisToken.thisToken != Tokenizer::Token::End && thisToken.thisToken != Tokenizer::Token::RBrace && thisToken.thisToken != Tokenizer::Token::LBrace) {
        	decltype(Parser::bigType) test = 0.0;
            if (thisToken.thisToken == Tokenizer::Token::Plus) {

            	test = (decltype(Parser::bigType))c + (decltype(Parser::bigType))term(text);
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else if (thisToken.thisToken == Tokenizer::Token::Minus) {

            	test = (decltype(Parser::bigType))c - (decltype(Parser::bigType))term(text);
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else
                throw std::runtime_error("Syntax error");
        }
        if (thisToken.thisToken == Tokenizer::Token::LBrace){
            throw std::runtime_error("Brace syntax error");
        }
        if (thisToken.thisToken != Tokenizer::Token::RBrace || fromPrim){
            return c;
        }
        throw std::runtime_error("Brace syntax error");
    }
    const char* expression;
    std::unordered_map<std::string, double> constants =
            {
                    { "Pi", M_PI },
                    { "e", M_E }
            };
    Tokenizer thisToken;

};

void checkErrors(bool a){
	if(!a)
		std::cout << "error" << std::endl;
	return;
}

bool isEqual(const double &left, const double &right){
	return fabs(left - right) < DBL_EPSILON;
}

int main(int argc, char* argv[]) {

    /*if(argc<2){
        throw std::runtime_error("No input expression");
    }
	const char* expression = argv[1];
    calculator<int,Parser<int>>(expression).calculate();
    *///  I do without args/uncomment and use if needed
    if(argc>1){
    	//const char* expression = argv[1];
    	//calculator<int,Parser<int>>(expression).calculate();
    }

    char* Expr1 = new char[255];
    std::strcpy(Expr1, std::string("3+3").c_str());
    char* Expr2 = new char[255];
    std::strcpy(Expr2, std::string("9/2*2").c_str());
    char* Expr3 = new char[255];
    std::strcpy(Expr3, std::string("Pi*-e").c_str());
    char* Expr4 = new char[255];
    std::strcpy(Expr4, std::string("8*Pi").c_str());

    //DOUBLE

    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr1),(double)6));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr2),(double)9));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr3),(double)-M_PI*M_E));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr4),(double)M_PI*8));

    //INT

    checkErrors(calculator<int,Parser<int>>().calculate(Expr1)==6);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr2)==8);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr3)==-6);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr4)==24);

    //LONG

    checkErrors(calculator<long,Parser<long>>().calculate(Expr1)==6);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr2)==8);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr3)==-6);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr4)==24);

    return 0;
}<commit_msg>Fixed memory allocation<commit_after>#include <iostream>
#include <unordered_map>
#include <cstring>
#include <limits>
#include <cmath>
#include <cfloat>

class Tokenizer {
public:
    void updateToken(
            const char *&text) //Указатель будет сдвигаться. Текст - это ссылка на указатель константной char. Не смогу менять то, что внутри, но указатель смогу.
    {
        while (const auto c = *text++) {//Когда встретит 0 - остановится. Приоритет выше у инкремента - прибавим сначала, но разыменуем предыдущий указатель
            switch (c) {
                case ' ':
                    continue;
                case '-':
                    thisToken = Token::Minus;
                    return;
                case '+':
                    thisToken = Token::Plus;
                    return;
                case '*':
                    thisToken = Token::Mul;
                    return;
                case '/':
                    thisToken = Token::Div;
                    return;
                case '(':
                    thisToken = Token::LBrace;
                    return;
                case ')':
                    thisToken = Token::RBrace;
                    return;
            }
            if (c >= '0' && c <= '9') {
                thisToken = Token::Number;
                return;
            }
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
                thisToken = Token::Const;
                return;
            }
            throw std::runtime_error("Invalid Symbol"); // Вместо return Token::Invalid;
        }
        thisToken = Token::End;
        return;
    }

    enum class Token {
        Minus,
        Plus,
        Mul,
        Div,
        Number,
        End,
        Const,
        LBrace,
        RBrace
    };

    Token thisToken;
};

template <class T>
struct Parser
{
};
template <class T>
struct NumericTraits
{
};

template<> struct NumericTraits<double>{
    static constexpr double min = std::numeric_limits<double>::min();
    static constexpr double max = std::numeric_limits<double>::max();
};

template <>
struct NumericTraits<int>{
    static constexpr int min = std::numeric_limits<int>::min();
    static constexpr int max = std::numeric_limits<int>::max();
};

template <>
struct NumericTraits<long>{
    static constexpr long min = std::numeric_limits<long>::min();
    static constexpr long max = std::numeric_limits<long>::max();
};

template<>
struct Parser<int>
{
  static bool parse(const char*& text, int& value)
  {
  	long tmp = long(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + long(*text - '0');
        }
  if(tmp < NumericTraits<int>::min || tmp > NumericTraits<int>::max)
  	return false;
  value = tmp;
  return true;
  }
  static long bigType;
  static bool checkType(long &a){
  	if(a > NumericTraits<int>::max || a < - NumericTraits<int>::max){
  		return false;
  	}
  	return true;
  }
};

template<>
struct Parser<long>
{
  static bool parse(const char*& text, long& value)
  {
  	long long tmp = (long long)(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + (long long)(*text - '0');
        }
  if(tmp < NumericTraits<long>::min || tmp > NumericTraits<long>::max)
  	return false;
  value = tmp;
  return true;
  }
  static long long bigType;
  static bool checkType(long long &a){
  	if(a > NumericTraits<long>::max || a < - NumericTraits<long>::max){
  		return false;
  	}
  	return true;
  }
};

template<>
struct Parser<double>
{
  static bool parse(const char*& text, double& value)
  {
  	long double tmp = (long double)(*text - '0');
        while (*(++text) >= '0' && *text <= '9') {
            tmp = tmp * 10 + (long double)(*text - '0');
        }
        if((*text == '.') && (*(++text) >= '0' || *(text) <= '9')){
        	tmp += (long double)(*text - '0') / 10;
        	int power = -1;
        	while (*(++text) >= '0' && *text <= '9') {
        		--power;
            	tmp +=  (long double)(*text - '0') * pow(10.0, power);
        	}
    	}
  	if(!std::isfinite(tmp)){//Требуется, потому что в случае проверки NumericTraits 0.0 не пройдет проверку.
  		return false;
  	}
  	if(tmp > NumericTraits<double>::max){
  		return false;
  	}
  	value = tmp;
  	return true;
  }

  static bool checkType(long double &a){
  	if(!std::isfinite((double)a)){//Требуется, потому что в случае проверки NumericTraits 0.0 не пройдет проверку.
  		return false;
  	}
  	if(a > NumericTraits<double>::max || a < - NumericTraits<double>::max){
  		return false;
  	}
  	return true;
  }
  static long double bigType;
};

template <class T, class Parser>
class calculator {
public:
    calculator(char *&text){
        expression = text;
    }
    calculator(){

    }

    T calculate(char *&text){
    	expression = text;
    	T result = expr(expression);
        std::cout << result << std::endl;
        return result;
    }

    /*void setExpr(std::string expr){
    	//this->expression = expr;
    	strcpy(this->expression, expr.c_str());
    }*/

private:
    T prim(const char *&text) {
        bool isPositive = true;
        thisToken.updateToken(text);
        --text;
        if (thisToken.thisToken == Tokenizer::Token::Minus) { //Checking if number is positive/negative
            isPositive = false;
            thisToken.updateToken(++text); //Checking what goes after subtraction symbol
            --text;
        }
        if(thisToken.thisToken == Tokenizer::Token::LBrace){//If there are braces - create loop to calculate expr in braces.
            ++text;
            T c = expr(text, true);
            return c * (2 * isPositive - 1);
        }
        if (thisToken.thisToken == Tokenizer::Token::End) {
            return 0;
        }
        if (thisToken.thisToken == Tokenizer::Token::Const){
            int length = 1;
            ++text ;
            while ((*text >= 'A' && *text <= 'Z') || (*text >= 'a' && *text <= 'z')) {
                length += 1;
                ++text;
            }
            std::string var;
            //auto* var = new std::string();
            var.assign(text-length, length);
            return constants.at(var) * (2 * isPositive - 1);
        }
        if (thisToken.thisToken != Tokenizer::Token::Number) {
            throw std::runtime_error("Syntax error");
        }
        T c;
        if(!Parser::parse(text, c))
    		throw std::runtime_error ("Syntax error: number can not be read");

        return c * (2 * isPositive - 1);

    }

    T term(const char *&text) {
        T c = prim(text);
        thisToken.updateToken(text);
        while (thisToken.thisToken == Tokenizer::Token::Mul || thisToken.thisToken == Tokenizer::Token::Div) {

            decltype(Parser::bigType) test = 0.0;
            if (thisToken.thisToken == Tokenizer::Token::Mul) {

            	test = (decltype(Parser::bigType))c * (decltype(Parser::bigType))prim(text);
            	if(Parser::checkType(test)){
            		c = T(test);
            	}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else {
                T divider = prim(text);
                if (divider) {

                	test = (decltype(Parser::bigType))c / (decltype(Parser::bigType))divider;
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                    thisToken.updateToken(text);
                } else throw std::runtime_error("Division by zero");
            }
        }
        --text;
        return c;
    }

    T expr(const char *&text, bool fromPrim = false) {
        T c = term(text);
        thisToken.updateToken(text);
        while (thisToken.thisToken != Tokenizer::Token::End && thisToken.thisToken != Tokenizer::Token::RBrace && thisToken.thisToken != Tokenizer::Token::LBrace) {
        	decltype(Parser::bigType) test = 0.0;
            if (thisToken.thisToken == Tokenizer::Token::Plus) {

            	test = (decltype(Parser::bigType))c + (decltype(Parser::bigType))term(text);
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else if (thisToken.thisToken == Tokenizer::Token::Minus) {

            	test = (decltype(Parser::bigType))c - (decltype(Parser::bigType))term(text);
            		if(Parser::checkType(test)){
            			c = T(test);
            		}else throw std::runtime_error("Result left type limits");

                thisToken.updateToken(text);
            } else
                throw std::runtime_error("Syntax error");
        }
        if (thisToken.thisToken == Tokenizer::Token::LBrace){
            throw std::runtime_error("Brace syntax error");
        }
        if (thisToken.thisToken != Tokenizer::Token::RBrace || fromPrim){
            return c;
        }
        throw std::runtime_error("Brace syntax error");
    }
    const char* expression;
    std::unordered_map<std::string, double> constants =
            {
                    { "Pi", M_PI },
                    { "e", M_E }
            };
    Tokenizer thisToken;

};

void checkErrors(bool a){
	if(!a)
		std::cout << "error" << std::endl;
	return;
}

bool isEqual(const double &left, const double &right){
	return fabs(left - right) < DBL_EPSILON;
}

int main(int argc, char* argv[]) {

    /*if(argc<2){
        throw std::runtime_error("No input expression");
    }
	const char* expression = argv[1];
    calculator<int,Parser<int>>(expression).calculate();
    *///  I do without args/uncomment and use if needed
    if(argc>1){
    	//const char* expression = argv[1];
    	//calculator<int,Parser<int>>(expression).calculate();
    }

    char* Expr1 = new char[255];
    std::strcpy(Expr1, std::string("3+3").c_str());
    char* Expr2 = new char[255];
    std::strcpy(Expr2, std::string("9/2*2").c_str());
    char* Expr3 = new char[255];
    std::strcpy(Expr3, std::string("Pi*-e").c_str());
    char* Expr4 = new char[255];
    std::strcpy(Expr4, std::string("8*Pi").c_str());

    //DOUBLE

    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr1),(double)6));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr2),(double)9));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr3),(double)-M_PI*M_E));
    checkErrors(isEqual(calculator<double,Parser<double>>().calculate(Expr4),(double)M_PI*8));

    //INT

    checkErrors(calculator<int,Parser<int>>().calculate(Expr1)==6);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr2)==8);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr3)==-6);
    checkErrors(calculator<int,Parser<int>>().calculate(Expr4)==24);

    //LONG

    checkErrors(calculator<long,Parser<long>>().calculate(Expr1)==6);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr2)==8);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr3)==-6);
    checkErrors(calculator<long,Parser<long>>().calculate(Expr4)==24);

    delete [] Expr1;
    delete [] Expr2;
    delete [] Expr3;
    delete [] Expr4;

    return 0;
}<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Portions based heavily on:
// third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.cpp
//
/*
 * Copyright (C) 2006-2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "content/browser/renderer_host/web_input_event_aura.h"

#include <cstdlib>
#include <X11/Xlib.h>

#include "base/event_types.h"
#include "base/logging.h"
#include "ui/aura/event.h"
#include "ui/base/events.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"

namespace content {

// chromium WebKit does not provide a WebInputEventFactory for X11, so we have
// to do the work here ourselves.

namespace {

double XEventTimeToWebEventTime(Time time) {
  // Convert from time in ms to time in s.
  return time / 1000.0;
}

int EventFlagsToWebEventModifiers(int flags) {
  int modifiers = 0;
  if (flags & ui::EF_SHIFT_DOWN)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (flags & ui::EF_CONTROL_DOWN)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (flags & ui::EF_ALT_DOWN)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (flags & ui::EF_LEFT_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (flags & ui::EF_MIDDLE_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (flags & ui::EF_RIGHT_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (flags & ui::EF_CAPS_LOCK_DOWN)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  return modifiers;
}

int XStateToWebEventModifiers(unsigned int state) {
  int modifiers = 0;
  if (state & ShiftMask)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (state & ControlMask)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (state & Mod1Mask)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (state & Button1Mask)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (state & Button2Mask)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (state & Button3Mask)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (state & LockMask)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  if (state & Mod2Mask)
    modifiers |= WebKit::WebInputEvent::NumLockOn;
  return modifiers;
}

int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
  return ui::KeyboardCodeFromXKeyEvent((XEvent*)event);
}

// From
// third_party/WebKit/Source/WebKit/chromium/src/gtk/WebInputEventFactory.cpp:
WebKit::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
  if (windows_key_code >= ui::VKEY_A &&
    windows_key_code <= ui::VKEY_Z) {
    // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
    return windows_key_code - ui::VKEY_A + 1;
  }
  if (shift) {
    // following graphics chars require shift key to input.
    switch (windows_key_code) {
      // ctrl-@ maps to \x00 (Null byte)
      case ui::VKEY_2:
        return 0;
      // ctrl-^ maps to \x1E (Record separator, Information separator two)
      case ui::VKEY_6:
        return 0x1E;
      // ctrl-_ maps to \x1F (Unit separator, Information separator one)
      case ui::VKEY_OEM_MINUS:
        return 0x1F;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  } else {
    switch (windows_key_code) {
      // ctrl-[ maps to \x1B (Escape)
      case ui::VKEY_OEM_4:
        return 0x1B;
      // ctrl-\ maps to \x1C (File separator, Information separator four)
      case ui::VKEY_OEM_5:
        return 0x1C;
      // ctrl-] maps to \x1D (Group separator, Information separator three)
      case ui::VKEY_OEM_6:
        return 0x1D;
      // ctrl-Enter maps to \x0A (Line feed)
      case ui::VKEY_RETURN:
        return 0x0A;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  }
  return 0;
}

WebKit::WebMouseEvent::Button ButtonFromXButton(int button) {
  switch (button) {
    case 1:
      return WebKit::WebMouseEvent::ButtonLeft;
    case 2:
      return WebKit::WebMouseEvent::ButtonMiddle;
    case 3:
      return WebKit::WebMouseEvent::ButtonRight;
    default:
      break;
  }
  return WebKit::WebMouseEvent::ButtonNone;
}

WebKit::WebMouseEvent::Button ButtonFromXState(int state) {
  if (state & Button1MotionMask)
    return WebKit::WebMouseEvent::ButtonLeft;
  if (state & Button2MotionMask)
    return WebKit::WebMouseEvent::ButtonMiddle;
  if (state & Button3MotionMask)
    return WebKit::WebMouseEvent::ButtonRight;
  return WebKit::WebMouseEvent::ButtonNone;
}

// We have to count clicks (for double-clicks) manually.
unsigned int g_num_clicks = 0;
double g_last_click_time = 0.0;
int g_last_click_x = 0;
int g_last_click_y = 0;
WebKit::WebMouseEvent::Button g_last_click_button =
    WebKit::WebMouseEvent::ButtonNone;

bool ShouldForgetPreviousClick(double time, int x, int y) {
  const double double_click_time = 0.250;  // in seconds
  const int double_click_distance = 5;
  return (time - g_last_click_time) > double_click_time ||
      std::abs(x - g_last_click_x) > double_click_distance ||
      std::abs(y - g_last_click_y) > double_click_distance;
}

void ResetClickCountState() {
  g_num_clicks = 0;
  g_last_click_time = 0.0;
  g_last_click_x = 0;
  g_last_click_y = 0;
  g_last_click_button = WebKit::WebMouseEvent::ButtonNone;
}

}  // namespace

WebKit::WebMouseEvent MakeWebMouseEventFromAuraEvent(aura::MouseEvent* event) {
  WebKit::WebMouseEvent webkit_event;

  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().ToDoubleT();

  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  if (event->flags() & ui::EF_LEFT_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonLeft;
  if (event->flags() & ui::EF_MIDDLE_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  if (event->flags() & ui::EF_RIGHT_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonRight;

  switch (event->type()) {
    case ui::ET_MOUSE_PRESSED:
      webkit_event.type = WebKit::WebInputEvent::MouseDown;
      if (!ShouldForgetPreviousClick(event->time_stamp().ToDoubleT(),
            event->location().x(), event->location().y()) &&
          webkit_event.button == g_last_click_button) {
        ++g_num_clicks;
      } else {
        g_num_clicks = 1;
        g_last_click_time = event->time_stamp().ToDoubleT();
        g_last_click_x = event->location().x();
        g_last_click_y = event->location().y();
        g_last_click_button = webkit_event.button;
      }
      webkit_event.clickCount = g_num_clicks;
      break;
    case ui::ET_MOUSE_RELEASED:
      webkit_event.type = WebKit::WebInputEvent::MouseUp;
      break;
    case ui::ET_MOUSE_ENTERED:
    case ui::ET_MOUSE_EXITED:
    case ui::ET_MOUSE_MOVED:
    case ui::ET_MOUSE_DRAGGED:
      webkit_event.type = WebKit::WebInputEvent::MouseMove;
      if (ShouldForgetPreviousClick(event->time_stamp().ToDoubleT(),
            event->location().x(), event->location().y()))
        ResetClickCountState();
      break;
    default:
      NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
      break;
  }

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::MouseEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;
  // TODO(sadrul): !
  return webkit_event;
}

WebKit::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
    aura::KeyEvent* event) {
  base::NativeEvent native_event = event->native_event();
  WebKit::WebKeyboardEvent webkit_event;
  XKeyEvent* native_key_event = &native_event->xkey;

  webkit_event.timeStampSeconds =
      XEventTimeToWebEventTime(native_key_event->time);
  webkit_event.modifiers = XStateToWebEventModifiers(native_key_event->state);

  switch (native_event->type) {
    case KeyPress:
      webkit_event.type = event->is_char() ? WebKit::WebInputEvent::Char :
          WebKit::WebInputEvent::RawKeyDown;
      break;
    case KeyRelease:
      webkit_event.type = WebKit::WebInputEvent::KeyUp;
      break;
    case GenericEvent:
      // TODO(sadrul): touch!
      break;
    default:
      NOTREACHED();
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::AltKey)
    webkit_event.isSystemKey = true;

  webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
  webkit_event.nativeKeyCode = native_key_event->keycode;

  if (webkit_event.windowsKeyCode == ui::VKEY_RETURN) {
    webkit_event.unmodifiedText[0] = '\r';
  } else {
    webkit_event.unmodifiedText[0] =
        ui::DefaultXKeysymFromHardwareKeycode(native_key_event->keycode);
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::ControlKey) {
    webkit_event.text[0] =
        GetControlCharacter(
            webkit_event.windowsKeyCode,
            webkit_event.modifiers & WebKit::WebInputEvent::ShiftKey);
  } else {
    webkit_event.text[0] = webkit_event.unmodifiedText[0];
  }

  webkit_event.setKeyIdentifierFromWindowsKeyCode();

  // TODO: IsAutoRepeat/IsKeyPad?

  return webkit_event;
}

}  // namespace content
<commit_msg>aura: Add mouse wheel event support for x11 in RWHVA.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Portions based heavily on:
// third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.cpp
//
/*
 * Copyright (C) 2006-2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "content/browser/renderer_host/web_input_event_aura.h"

#include <cstdlib>
#include <X11/Xlib.h>

#include "base/event_types.h"
#include "base/logging.h"
#include "ui/aura/event.h"
#include "ui/base/events.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"

namespace content {

// chromium WebKit does not provide a WebInputEventFactory for X11, so we have
// to do the work here ourselves.

namespace {

double XEventTimeToWebEventTime(Time time) {
  // Convert from time in ms to time in s.
  return time / 1000.0;
}

int EventFlagsToWebEventModifiers(int flags) {
  int modifiers = 0;
  if (flags & ui::EF_SHIFT_DOWN)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (flags & ui::EF_CONTROL_DOWN)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (flags & ui::EF_ALT_DOWN)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (flags & ui::EF_LEFT_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (flags & ui::EF_MIDDLE_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (flags & ui::EF_RIGHT_BUTTON_DOWN)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (flags & ui::EF_CAPS_LOCK_DOWN)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  return modifiers;
}

int XStateToWebEventModifiers(unsigned int state) {
  int modifiers = 0;
  if (state & ShiftMask)
    modifiers |= WebKit::WebInputEvent::ShiftKey;
  if (state & ControlMask)
    modifiers |= WebKit::WebInputEvent::ControlKey;
  if (state & Mod1Mask)
    modifiers |= WebKit::WebInputEvent::AltKey;
  // TODO(beng): MetaKey/META_MASK
  if (state & Button1Mask)
    modifiers |= WebKit::WebInputEvent::LeftButtonDown;
  if (state & Button2Mask)
    modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
  if (state & Button3Mask)
    modifiers |= WebKit::WebInputEvent::RightButtonDown;
  if (state & LockMask)
    modifiers |= WebKit::WebInputEvent::CapsLockOn;
  if (state & Mod2Mask)
    modifiers |= WebKit::WebInputEvent::NumLockOn;
  return modifiers;
}

int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
  return ui::KeyboardCodeFromXKeyEvent((XEvent*)event);
}

// From
// third_party/WebKit/Source/WebKit/chromium/src/gtk/WebInputEventFactory.cpp:
WebKit::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
  if (windows_key_code >= ui::VKEY_A &&
    windows_key_code <= ui::VKEY_Z) {
    // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
    return windows_key_code - ui::VKEY_A + 1;
  }
  if (shift) {
    // following graphics chars require shift key to input.
    switch (windows_key_code) {
      // ctrl-@ maps to \x00 (Null byte)
      case ui::VKEY_2:
        return 0;
      // ctrl-^ maps to \x1E (Record separator, Information separator two)
      case ui::VKEY_6:
        return 0x1E;
      // ctrl-_ maps to \x1F (Unit separator, Information separator one)
      case ui::VKEY_OEM_MINUS:
        return 0x1F;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  } else {
    switch (windows_key_code) {
      // ctrl-[ maps to \x1B (Escape)
      case ui::VKEY_OEM_4:
        return 0x1B;
      // ctrl-\ maps to \x1C (File separator, Information separator four)
      case ui::VKEY_OEM_5:
        return 0x1C;
      // ctrl-] maps to \x1D (Group separator, Information separator three)
      case ui::VKEY_OEM_6:
        return 0x1D;
      // ctrl-Enter maps to \x0A (Line feed)
      case ui::VKEY_RETURN:
        return 0x0A;
      // Returns 0 for all other keys to avoid inputting unexpected chars.
      default:
        break;
    }
  }
  return 0;
}

WebKit::WebMouseEvent::Button ButtonFromXButton(int button) {
  switch (button) {
    case 1:
      return WebKit::WebMouseEvent::ButtonLeft;
    case 2:
      return WebKit::WebMouseEvent::ButtonMiddle;
    case 3:
      return WebKit::WebMouseEvent::ButtonRight;
    default:
      break;
  }
  return WebKit::WebMouseEvent::ButtonNone;
}

WebKit::WebMouseEvent::Button ButtonFromXState(int state) {
  if (state & Button1MotionMask)
    return WebKit::WebMouseEvent::ButtonLeft;
  if (state & Button2MotionMask)
    return WebKit::WebMouseEvent::ButtonMiddle;
  if (state & Button3MotionMask)
    return WebKit::WebMouseEvent::ButtonRight;
  return WebKit::WebMouseEvent::ButtonNone;
}

// We have to count clicks (for double-clicks) manually.
unsigned int g_num_clicks = 0;
double g_last_click_time = 0.0;
int g_last_click_x = 0;
int g_last_click_y = 0;
WebKit::WebMouseEvent::Button g_last_click_button =
    WebKit::WebMouseEvent::ButtonNone;

bool ShouldForgetPreviousClick(double time, int x, int y) {
  const double double_click_time = 0.250;  // in seconds
  const int double_click_distance = 5;
  return (time - g_last_click_time) > double_click_time ||
      std::abs(x - g_last_click_x) > double_click_distance ||
      std::abs(y - g_last_click_y) > double_click_distance;
}

void ResetClickCountState() {
  g_num_clicks = 0;
  g_last_click_time = 0.0;
  g_last_click_x = 0;
  g_last_click_y = 0;
  g_last_click_button = WebKit::WebMouseEvent::ButtonNone;
}

}  // namespace

WebKit::WebMouseEvent MakeWebMouseEventFromAuraEvent(aura::MouseEvent* event) {
  WebKit::WebMouseEvent webkit_event;

  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().ToDoubleT();

  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  if (event->flags() & ui::EF_LEFT_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonLeft;
  if (event->flags() & ui::EF_MIDDLE_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonMiddle;
  if (event->flags() & ui::EF_RIGHT_BUTTON_DOWN)
    webkit_event.button = WebKit::WebMouseEvent::ButtonRight;

  switch (event->type()) {
    case ui::ET_MOUSE_PRESSED:
      webkit_event.type = WebKit::WebInputEvent::MouseDown;
      if (!ShouldForgetPreviousClick(event->time_stamp().ToDoubleT(),
            event->location().x(), event->location().y()) &&
          webkit_event.button == g_last_click_button) {
        ++g_num_clicks;
      } else {
        g_num_clicks = 1;
        g_last_click_time = event->time_stamp().ToDoubleT();
        g_last_click_x = event->location().x();
        g_last_click_y = event->location().y();
        g_last_click_button = webkit_event.button;
      }
      webkit_event.clickCount = g_num_clicks;
      break;
    case ui::ET_MOUSE_RELEASED:
      webkit_event.type = WebKit::WebInputEvent::MouseUp;
      break;
    case ui::ET_MOUSE_ENTERED:
    case ui::ET_MOUSE_EXITED:
    case ui::ET_MOUSE_MOVED:
    case ui::ET_MOUSE_DRAGGED:
      webkit_event.type = WebKit::WebInputEvent::MouseMove;
      if (ShouldForgetPreviousClick(event->time_stamp().ToDoubleT(),
            event->location().x(), event->location().y()))
        ResetClickCountState();
      break;
    default:
      NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
      break;
  }

  return webkit_event;
}

WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    aura::MouseEvent* event) {
  WebKit::WebMouseWheelEvent webkit_event;

  webkit_event.type = WebKit::WebInputEvent::MouseWheel;
  webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
  webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
  webkit_event.timeStampSeconds = event->time_stamp().ToDoubleT();
  webkit_event.deltaY = ui::GetMouseWheelOffset(event->native_event());
  webkit_event.wheelTicksY = webkit_event.deltaY > 0 ? 1 : -1;

  return webkit_event;
}

WebKit::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
    aura::KeyEvent* event) {
  base::NativeEvent native_event = event->native_event();
  WebKit::WebKeyboardEvent webkit_event;
  XKeyEvent* native_key_event = &native_event->xkey;

  webkit_event.timeStampSeconds =
      XEventTimeToWebEventTime(native_key_event->time);
  webkit_event.modifiers = XStateToWebEventModifiers(native_key_event->state);

  switch (native_event->type) {
    case KeyPress:
      webkit_event.type = event->is_char() ? WebKit::WebInputEvent::Char :
          WebKit::WebInputEvent::RawKeyDown;
      break;
    case KeyRelease:
      webkit_event.type = WebKit::WebInputEvent::KeyUp;
      break;
    case GenericEvent:
      // TODO(sadrul): touch!
      break;
    default:
      NOTREACHED();
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::AltKey)
    webkit_event.isSystemKey = true;

  webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
  webkit_event.nativeKeyCode = native_key_event->keycode;

  if (webkit_event.windowsKeyCode == ui::VKEY_RETURN) {
    webkit_event.unmodifiedText[0] = '\r';
  } else {
    webkit_event.unmodifiedText[0] =
        ui::DefaultXKeysymFromHardwareKeycode(native_key_event->keycode);
  }

  if (webkit_event.modifiers & WebKit::WebInputEvent::ControlKey) {
    webkit_event.text[0] =
        GetControlCharacter(
            webkit_event.windowsKeyCode,
            webkit_event.modifiers & WebKit::WebInputEvent::ShiftKey);
  } else {
    webkit_event.text[0] = webkit_event.unmodifiedText[0];
  }

  webkit_event.setKeyIdentifierFromWindowsKeyCode();

  // TODO: IsAutoRepeat/IsKeyPad?

  return webkit_event;
}

}  // namespace content
<|endoftext|>