<commit_before>/*************************************************************************/
/*  godot_win.cpp                                                        */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "os_windows.h"
#include "main/main.h"
#include <stdio.h>
#include <locale.h>

PCHAR*
    CommandLineToArgvA(
        PCHAR CmdLine,
        int* _argc
        )
    {
        PCHAR* argv;
        PCHAR  _argv;
        ULONG   len;
        ULONG   argc;
        CHAR   a;
        ULONG   i, j;

        BOOLEAN  in_QM;
        BOOLEAN  in_TEXT;
        BOOLEAN  in_SPACE;

        len = strlen(CmdLine);
        i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);

        argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
            i + (len+2)*sizeof(CHAR));

        _argv = (PCHAR)(((PUCHAR)argv)+i);

        argc = 0;
        argv[argc] = _argv;
        in_QM = FALSE;
        in_TEXT = FALSE;
        in_SPACE = TRUE;
        i = 0;
        j = 0;

        while( (a = CmdLine[i]) ) {
            if(in_QM) {
                if(a == '\"') {
                    in_QM = FALSE;
                } else {
                    _argv[j] = a;
                    j++;
                }
            } else {
                switch(a) {
                case '\"':
                    in_QM = TRUE;
                    in_TEXT = TRUE;
                    if(in_SPACE) {
                        argv[argc] = _argv+j;
                        argc++;
                    }
                    in_SPACE = FALSE;
                    break;
                case ' ':
                case '\t':
                case '\n':
                case '\r':
                    if(in_TEXT) {
                        _argv[j] = '\0';
                        j++;
                    }
                    in_TEXT = FALSE;
                    in_SPACE = TRUE;
                    break;
                default:
                    in_TEXT = TRUE;
                    if(in_SPACE) {
                        argv[argc] = _argv+j;
                        argc++;
                    }
                    _argv[j] = a;
                    j++;
                    in_SPACE = FALSE;
                    break;
                }
            }
            i++;
        }
        _argv[j] = '\0';
        argv[argc] = NULL;

        (*_argc) = argc;
        return argv;
    }

char* mb_to_utf8(const char* mbs) {

	int wlen = MultiByteToWideChar(CP_ACP,0,mbs,-1,NULL,0); // returns 0 if failed
	wchar_t *wbuf = new wchar_t[wlen + 1];
	MultiByteToWideChar(CP_ACP,0,mbs,-1,wbuf,wlen);
	wbuf[wlen]=0;

	int ulen = WideCharToMultiByte(CP_UTF8,0,wbuf,-1,NULL,0,NULL,NULL);
	char * ubuf = new char[ulen + 1];
	WideCharToMultiByte(CP_UTF8,0,wbuf,-1,ubuf,ulen,NULL,NULL);
	ubuf[ulen] = 0;
	return ubuf;
}

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

	OS_Windows os(NULL);

	setlocale(LC_CTYPE, "");

	char ** argv_utf8 = new char*[argc];
	for(int i=0; i<argc; ++i) {
		argv_utf8[i] = mb_to_utf8(argv[i]);
	}

	Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
	if (Main::start())
		os.run();
	Main::cleanup();

	for (int i=0; i<argc; ++i) {
		delete[] argv_utf8[i];
	}
	delete[] argv_utf8;

	return os.get_exit_code();
};

HINSTANCE godot_hinstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)	{

    int    argc;
    char** argv;

    char*  arg;
    int    index;
    int    result;

    // count the arguments

    argc = 1;
    arg  = lpCmdLine;

    while (arg[0] != 0) {

        while (arg[0] != 0 && arg[0] == ' ') {
            arg++;
        }

        if (arg[0] != 0) {

            argc++;

            while (arg[0] != 0 && arg[0] != ' ') {
                arg++;
            }

        }

    }

    // tokenize the arguments

    argv = (char**)malloc(argc * sizeof(char*));

    arg = lpCmdLine;
    index = 1;

    while (arg[0] != 0) {

        while (arg[0] != 0 && arg[0] == ' ') {
            arg++;
        }

        if (arg[0] != 0) {

            argv[index] = arg;
            index++;

            while (arg[0] != 0 && arg[0] != ' ') {
                arg++;
            }

            if (arg[0] != 0) {
                arg[0] = 0;
                arg++;
            }

        }

    }

    // put the program name into argv[0]

    char filename[_MAX_PATH];

    GetModuleFileName(NULL, filename, _MAX_PATH);
    argv[0] = filename;

    // call the user specified main function

    result = main(argc, argv);

    free(argv);
    return result;
}
<commit_msg>fixes issue #1693 winmain and main unicode<commit_after>/*************************************************************************/
/*  godot_win.cpp                                                        */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "os_windows.h"
#include "main/main.h"
#include <stdio.h>
#include <locale.h>

PCHAR*
    CommandLineToArgvA(
        PCHAR CmdLine,
        int* _argc
        )
    {
        PCHAR* argv;
        PCHAR  _argv;
        ULONG   len;
        ULONG   argc;
        CHAR   a;
        ULONG   i, j;

        BOOLEAN  in_QM;
        BOOLEAN  in_TEXT;
        BOOLEAN  in_SPACE;

        len = strlen(CmdLine);
        i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);

        argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
            i + (len+2)*sizeof(CHAR));

        _argv = (PCHAR)(((PUCHAR)argv)+i);

        argc = 0;
        argv[argc] = _argv;
        in_QM = FALSE;
        in_TEXT = FALSE;
        in_SPACE = TRUE;
        i = 0;
        j = 0;

        while( (a = CmdLine[i]) ) {
            if(in_QM) {
                if(a == '\"') {
                    in_QM = FALSE;
                } else {
                    _argv[j] = a;
                    j++;
                }
            } else {
                switch(a) {
                case '\"':
                    in_QM = TRUE;
                    in_TEXT = TRUE;
                    if(in_SPACE) {
                        argv[argc] = _argv+j;
                        argc++;
                    }
                    in_SPACE = FALSE;
                    break;
                case ' ':
                case '\t':
                case '\n':
                case '\r':
                    if(in_TEXT) {
                        _argv[j] = '\0';
                        j++;
                    }
                    in_TEXT = FALSE;
                    in_SPACE = TRUE;
                    break;
                default:
                    in_TEXT = TRUE;
                    if(in_SPACE) {
                        argv[argc] = _argv+j;
                        argc++;
                    }
                    _argv[j] = a;
                    j++;
                    in_SPACE = FALSE;
                    break;
                }
            }
            i++;
        }
        _argv[j] = '\0';
        argv[argc] = NULL;

        (*_argc) = argc;
        return argv;
    }

char* wc_to_utf8(const wchar_t* wc) {
	int ulen = WideCharToMultiByte(CP_UTF8,0,wc,-1,NULL,0,NULL,NULL);
	char * ubuf = new char[ulen + 1];
	WideCharToMultiByte(CP_UTF8,0,wc,-1,ubuf,ulen,NULL,NULL);
	ubuf[ulen] = 0;
	return ubuf;
}

int widechar_main(int argc, wchar_t** argv) {

	OS_Windows os(NULL);

	setlocale(LC_CTYPE, "");

	char ** argv_utf8 = new char*[argc];

	for(int i=0; i<argc; ++i) {
		argv_utf8[i] = wc_to_utf8(argv[i]);
	}

	Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
	if (Main::start())
		os.run();
	Main::cleanup();

	for (int i=0; i<argc; ++i) {
		delete[] argv_utf8[i];
	}
	delete[] argv_utf8;

	return os.get_exit_code();
};

int main(int _argc, char** _argv) {
	// _argc and _argv are ignored
	// we are going to use the WideChar version of them instead

	LPWSTR *wc_argv;
	int    argc;
	int    result;

	wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);

	if( NULL == wc_argv )	{
		wprintf(L"CommandLineToArgvW failed\n");
		return 0;
	}

	result = widechar_main(argc, wc_argv);

	LocalFree(wc_argv);
	return result;
}

HINSTANCE godot_hinstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)	{
	godot_hinstance = hInstance;
	return main(0,NULL);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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 "Box.h"

#include <gif_lib.h>
#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"
#include "http/HTTPRequest.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_gray_1_2_4_to_8(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

uint16_t readUint16(const char* p)
{
    return static_cast<uint16_t >(p[0]) + (static_cast<uint16_t >(p[1]) << 8);
}

unsigned char* expandColors(unsigned char* dst, unsigned char* src, unsigned count, int transparentIndex, GifColorType* colors)
{
    for (int i = 0; i < count; ++i, ++src) {
        if (*src == transparentIndex) {
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
        } else {
            GifColorType* color = &colors[*src];
            *dst++ = color->Red;
            *dst++ = color->Green;
            *dst++ = color->Blue;
            *dst++ = 255;
        }
    }
    return src;
}

unsigned char* readAsGif(FILE* file, unsigned& width, unsigned& height, unsigned& format, unsigned &frameCount, std::vector<uint16_t>& delays, unsigned& loop)
{
    unsigned char sig[6];
    if (fread(sig, 1, 6, file) != 6)
        return 0;
    if (memcmp(sig, GIF87_STAMP, 6) && memcmp(sig, GIF89_STAMP, 6))
        return 0;
    rewind(file);

    int fd = dup(fileno(file));
    lseek(fd, 0, SEEK_SET);
    GifFileType* gif = DGifOpenFileHandle(fd);
    if (!gif)
        return 0;
    if (DGifSlurp(gif) != GIF_OK || gif->ImageCount < 1) {
        DGifCloseFile(gif);
        return 0;
    }

    width = gif->SWidth;
    height = gif->SHeight;
    frameCount = gif->ImageCount;
    loop = 1;
    unsigned char* data = (unsigned char*) malloc(width * height * 4 * frameCount);
    if (!data) {
        DGifCloseFile(gif);
        return 0;
    }

    if (1 < frameCount)
        delays.resize(frameCount, 10);

    format = GL_RGBA;
    for (int frame = 0; frame < frameCount; ++frame) {
        SavedImage* image = &gif->SavedImages[frame];
        int transparentIndex = -1;
        int delay = 0;
        for (int i = 0; i < image->ExtensionBlockCount; ++i) {
            ExtensionBlock* ext = image->ExtensionBlocks + i;
            switch (ext->Function) {
            case GRAPHICS_EXT_FUNC_CODE:
                if (ext->ByteCount == 4) {
                    if ((ext->Bytes[0] & 1))    // transparent?
                        transparentIndex = ext->Bytes[3];
                    delays[frame] = readUint16(ext->Bytes + 1);
                }
                break;
            case APPLICATION_EXT_FUNC_CODE:
                if (ext->ByteCount == 11 && (!memcmp(ext->Bytes, "NETSCAPE2.0", 11) || !memcmp(ext->Bytes, "ANIMEXTS1.0", 11))) {
                    ++ext;  // Move to the sub-block
                    if (ext->ByteCount == 3) {
                        loop = readUint16(ext->Bytes + 1);
                    }
                }
                break;
            default:
                break;
            }
        }
        unsigned char* p0 = data + frame * width * height * 4;
        if (!gif->Image.Interlace)
            expandColors(p0, image->RasterBits, width * height, transparentIndex, gif->SColorMap->Colors);
        else {
            unsigned char* index = image->RasterBits;
            for (int row = 0; row < height; row += 8)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 4; row < height; row += 8)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 2; row < height; row += 4)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 1; row < height; row += 2)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
        }
    }
    DGifCloseFile(gif);
    return data;
}

}  // namespace

BoxImage::BoxImage(unsigned repeat) :
    state(Unavailable),
    flags(0),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    frameCount(1),
    delays(1),
    total(0.0f)
{
}

void BoxImage::open(FILE* file)
{
    assert(file);
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        rewind(file);
        pixels = readAsGif(file, naturalWidth, naturalHeight, format, frameCount, delays, loop);
    }
    if (!pixels) {
        state = Broken;
        return;
    }
    state = CompletelyAvailable;
    total = 0.0f;
    for (auto i = 0; i < delays.size(); ++i)
        total += delays[i];
}

unsigned BoxImage::getCurrentFrame(unsigned t, unsigned& delay, unsigned start)
{
    if (frameCount <= 1 || total == 0.0f)
        return 0;
    if (loop) {
        t -= start;
        if (total * loop <= t)
            return 0;
    }
    t %= total;
    unsigned d = 0.0f;
    for (unsigned i = 0; i < delays.size(); ++i) {
        d += delays[i];
        if (t < d) {
            delay = d - t;
            return i;
        }
    }
    return 0;
}

//
// HttpRequest
//

BoxImage* HttpRequest::getBoxImage(unsigned repeat)
{
    if (!boxImage)
        boxImage = new(std::nothrow) BoxImage(repeat);
    if (!boxImage)
        return 0;

    switch (getReadyState()) {
    case UNSENT:
        boxImage->setState(BoxImage::Unavailable);
        break;
    case OPENED:
    case HEADERS_RECEIVED:
    case LOADING:
    case COMPLETE:
        boxImage->setState(BoxImage::Sent);
        break;
    case DONE:
        if (boxImage->getState() < BoxImage::PartiallyAvailable) {
            if (getError()) {
                boxImage->setState(BoxImage::Unavailable);
                break;
            }
            if (FILE* file = openFile()) {
                boxImage->open(file);
                fclose(file);
            }
        }
        break;
    default:
        boxImage->setState(BoxImage::Unavailable);
        break;
    }
    return boxImage;
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(readAsPng) : Switch over to png_set_expand_gray_1_2_4_to_8; png_set_gray_1_2_4_to_8 has been deprecated.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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 "Box.h"

#include <gif_lib.h>
#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"
#include "http/HTTPRequest.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

uint16_t readUint16(const char* p)
{
    return static_cast<uint16_t >(p[0]) + (static_cast<uint16_t >(p[1]) << 8);
}

unsigned char* expandColors(unsigned char* dst, unsigned char* src, unsigned count, int transparentIndex, GifColorType* colors)
{
    for (int i = 0; i < count; ++i, ++src) {
        if (*src == transparentIndex) {
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
        } else {
            GifColorType* color = &colors[*src];
            *dst++ = color->Red;
            *dst++ = color->Green;
            *dst++ = color->Blue;
            *dst++ = 255;
        }
    }
    return src;
}

unsigned char* readAsGif(FILE* file, unsigned& width, unsigned& height, unsigned& format, unsigned &frameCount, std::vector<uint16_t>& delays, unsigned& loop)
{
    unsigned char sig[6];
    if (fread(sig, 1, 6, file) != 6)
        return 0;
    if (memcmp(sig, GIF87_STAMP, 6) && memcmp(sig, GIF89_STAMP, 6))
        return 0;
    rewind(file);

    int fd = dup(fileno(file));
    lseek(fd, 0, SEEK_SET);
    GifFileType* gif = DGifOpenFileHandle(fd);
    if (!gif)
        return 0;
    if (DGifSlurp(gif) != GIF_OK || gif->ImageCount < 1) {
        DGifCloseFile(gif);
        return 0;
    }

    width = gif->SWidth;
    height = gif->SHeight;
    frameCount = gif->ImageCount;
    loop = 1;
    unsigned char* data = (unsigned char*) malloc(width * height * 4 * frameCount);
    if (!data) {
        DGifCloseFile(gif);
        return 0;
    }

    if (1 < frameCount)
        delays.resize(frameCount, 10);

    format = GL_RGBA;
    for (int frame = 0; frame < frameCount; ++frame) {
        SavedImage* image = &gif->SavedImages[frame];
        int transparentIndex = -1;
        int delay = 0;
        for (int i = 0; i < image->ExtensionBlockCount; ++i) {
            ExtensionBlock* ext = image->ExtensionBlocks + i;
            switch (ext->Function) {
            case GRAPHICS_EXT_FUNC_CODE:
                if (ext->ByteCount == 4) {
                    if ((ext->Bytes[0] & 1))    // transparent?
                        transparentIndex = ext->Bytes[3];
                    delays[frame] = readUint16(ext->Bytes + 1);
                }
                break;
            case APPLICATION_EXT_FUNC_CODE:
                if (ext->ByteCount == 11 && (!memcmp(ext->Bytes, "NETSCAPE2.0", 11) || !memcmp(ext->Bytes, "ANIMEXTS1.0", 11))) {
                    ++ext;  // Move to the sub-block
                    if (ext->ByteCount == 3) {
                        loop = readUint16(ext->Bytes + 1);
                    }
                }
                break;
            default:
                break;
            }
        }
        unsigned char* p0 = data + frame * width * height * 4;
        if (!gif->Image.Interlace)
            expandColors(p0, image->RasterBits, width * height, transparentIndex, gif->SColorMap->Colors);
        else {
            unsigned char* index = image->RasterBits;
            for (int row = 0; row < height; row += 8)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 4; row < height; row += 8)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 2; row < height; row += 4)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
            for (int row = 1; row < height; row += 2)
                index = expandColors(p0 + width * row, index, width, transparentIndex, gif->SColorMap->Colors);
        }
    }
    DGifCloseFile(gif);
    return data;
}

}  // namespace

BoxImage::BoxImage(unsigned repeat) :
    state(Unavailable),
    flags(0),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    frameCount(1),
    delays(1),
    total(0.0f)
{
}

void BoxImage::open(FILE* file)
{
    assert(file);
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        rewind(file);
        pixels = readAsGif(file, naturalWidth, naturalHeight, format, frameCount, delays, loop);
    }
    if (!pixels) {
        state = Broken;
        return;
    }
    state = CompletelyAvailable;
    total = 0.0f;
    for (auto i = 0; i < delays.size(); ++i)
        total += delays[i];
}

unsigned BoxImage::getCurrentFrame(unsigned t, unsigned& delay, unsigned start)
{
    if (frameCount <= 1 || total == 0.0f)
        return 0;
    if (loop) {
        t -= start;
        if (total * loop <= t)
            return 0;
    }
    t %= total;
    unsigned d = 0.0f;
    for (unsigned i = 0; i < delays.size(); ++i) {
        d += delays[i];
        if (t < d) {
            delay = d - t;
            return i;
        }
    }
    return 0;
}

//
// HttpRequest
//

BoxImage* HttpRequest::getBoxImage(unsigned repeat)
{
    if (!boxImage)
        boxImage = new(std::nothrow) BoxImage(repeat);
    if (!boxImage)
        return 0;

    switch (getReadyState()) {
    case UNSENT:
        boxImage->setState(BoxImage::Unavailable);
        break;
    case OPENED:
    case HEADERS_RECEIVED:
    case LOADING:
    case COMPLETE:
        boxImage->setState(BoxImage::Sent);
        break;
    case DONE:
        if (boxImage->getState() < BoxImage::PartiallyAvailable) {
            if (getError()) {
                boxImage->setState(BoxImage::Unavailable);
                break;
            }
            if (FILE* file = openFile()) {
                boxImage->open(file);
                fclose(file);
            }
        }
        break;
    default:
        boxImage->setState(BoxImage::Unavailable);
        break;
    }
    return boxImage;
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include "functions/multiplication.hh"
#include "functions/full_function_defs.hh"
#include "functions/variables.hh"
#include "functions/polynomial.hh"
#include "functions/addition.hh"
#include "functions/operators.hh"
#include "functions/streaming.hh"

BOOST_AUTO_TEST_CASE(multiplication_test) {
  using namespace manifolds;
  Multiplication<decltype(x), decltype(z)> a(x, z);

  BOOST_CHECK_EQUAL(a(1, 2, 3, 4), 3);
  BOOST_CHECK_EQUAL(a(1, 2, 4, 8, 16), 4);

  auto f = Cos()(x * x) * y;
  BOOST_CHECK_EQUAL(f(2, 1), std::cos(4.0));
  auto f2 = -2_c * x * Sin()(x * x) * y;
  BOOST_CHECK_EQUAL((-2_c)(1), -2);
  BOOST_CHECK_EQUAL((-2_c * x * y)(2, 1), -4);
  BOOST_CHECK_EQUAL((Sin()(x * x))(2), std::sin(4));
  BOOST_CHECK_EQUAL((-2_c * Sin())(2), -2 * std::sin(2));
  BOOST_CHECK_EQUAL(f2(2, 1), -4 * std::sin(4));
}
<commit_msg>Improved test by a hair<commit_after>#include <boost/test/unit_test.hpp>
#include "functions/multiplication.hh"
#include "functions/full_function_defs.hh"
#include "functions/variables.hh"
#include "functions/polynomial.hh"
#include "functions/addition.hh"
#include "functions/operators.hh"
#include "functions/streaming.hh"

BOOST_AUTO_TEST_CASE(multiplication_test) {
  using namespace manifolds;
  Multiplication<decltype(x), decltype(z)> a(x, z);

  BOOST_CHECK_EQUAL(a(1, 2, 3, 4), 3);
  BOOST_CHECK_EQUAL(a(1, 2, 4, 8, 16), 4);

  auto f = Cos()(x * x) * y;
  BOOST_CHECK_EQUAL(f(2, 3), std::cos(4.0) * 3);
  auto f2 = -2_c * x * Sin()(x * x) * y;
  BOOST_CHECK_EQUAL((-2_c)(1), -2);
  BOOST_CHECK_EQUAL((-2_c * x * y)(2, 1), -4);
  BOOST_CHECK_EQUAL((Sin()(x * x))(2), std::sin(4));
  BOOST_CHECK_EQUAL((-2_c * Sin())(2), -2 * std::sin(2));
  BOOST_CHECK_EQUAL(f2(2, 1), -4 * std::sin(4));
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree.
 */
#ifdef DEBUG
#include "YGNodePrint.h"
#include <stdarg.h>
#include "YGEnums.h"
#include "YGNode.h"
#include "Yoga-internal.h"
#include "Utils.h"

namespace facebook {
namespace yoga {
typedef std::string string;

static void indent(string& base, uint32_t level) {
  for (uint32_t i = 0; i < level; ++i) {
    base.append("  ");
  }
}

static bool areFourValuesEqual(const YGStyle::Edges& four) {
  return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
      YGValueEqual(four[0], four[3]);
}

static void appendFormatedString(string& str, const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  va_list argsCopy;
  va_copy(argsCopy, args);
  std::vector<char> buf(1 + vsnprintf(NULL, 0, fmt, args));
  va_end(args);
  vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
  va_end(argsCopy);
  string result = string(buf.begin(), buf.end() - 1);
  str.append(result);
}

static void appendFloatOptionalIfDefined(
    string& base,
    const string key,
    const YGFloatOptional num) {
  if (!num.isUndefined()) {
    appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap());
  }
}

static void appendNumberIfNotUndefined(
    string& base,
    const string key,
    const YGValue number) {
  if (number.unit != YGUnitUndefined) {
    if (number.unit == YGUnitAuto) {
      base.append(key + ": auto; ");
    } else {
      string unit = number.unit == YGUnitPoint ? "px" : "%%";
      appendFormatedString(
          base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str());
    }
  }
}

static void appendNumberIfNotAuto(
    string& base,
    const string& key,
    const YGValue number) {
  if (number.unit != YGUnitAuto) {
    appendNumberIfNotUndefined(base, key, number);
  }
}

static void appendNumberIfNotZero(
    string& base,
    const string& str,
    const YGValue number) {
  if (number.unit == YGUnitAuto) {
    base.append(str + ": auto; ");
  } else if (!YGFloatsEqual(number.value, 0)) {
    appendNumberIfNotUndefined(base, str, number);
  }
}

static void appendEdges(
    string& base,
    const string& key,
    const YGStyle::Edges& edges) {
  if (areFourValuesEqual(edges)) {
    appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
  } else {
    for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
      string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
      appendNumberIfNotZero(base, str, edges[edge]);
    }
  }
}

static void appendEdgeIfNotUndefined(
    string& base,
    const string& str,
    const YGStyle::Edges& edges,
    const YGEdge edge) {
  appendNumberIfNotUndefined(
      base,
      str,
      YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined()));
}

void YGNodeToString(
    std::string& str,
    YGNodeRef node,
    YGPrintOptions options,
    uint32_t level) {
  indent(str, level);
  appendFormatedString(str, "
getLayout().dimensions[YGDimensionWidth]);
    appendFormatedString(
        str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]);
    appendFormatedString(
        str, "top: %g; ", node->getLayout().position[YGEdgeTop]);
    appendFormatedString(
        str, "left: %g;", node->getLayout().position[YGEdgeLeft]);
    appendFormatedString(str, "\" ");
  }

  if (options & YGPrintOptionsStyle) {
    appendFormatedString(str, "style=\"");
    if (node->getStyle().flexDirection() !=
        YGNode().getStyle().flexDirection()) {
      appendFormatedString(
          str,
          "flex-direction: %s; ",
          YGFlexDirectionToString(node->getStyle().flexDirection()));
    }
    if (node->getStyle().justifyContent() !=
        YGNode().getStyle().justifyContent()) {
      appendFormatedString(
          str,
          "justify-content: %s; ",
          YGJustifyToString(node->getStyle().justifyContent()));
    }
    if (node->getStyle().alignItems() != YGNode().getStyle().alignItems()) {
      appendFormatedString(
          str,
          "align-items: %s; ",
          YGAlignToString(node->getStyle().alignItems()));
    }
    if (node->getStyle().alignContent() != YGNode().getStyle().alignContent()) {
      appendFormatedString(
          str,
          "align-content: %s; ",
          YGAlignToString(node->getStyle().alignContent()));
    }
    if (node->getStyle().alignSelf() != YGNode().getStyle().alignSelf()) {
      appendFormatedString(
          str,
          "align-self: %s; ",
          YGAlignToString(node->getStyle().alignSelf()));
    }
    appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow());
    appendFloatOptionalIfDefined(
        str, "flex-shrink", node->getStyle().flexShrink());
    appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis());
    appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex());

    if (node->getStyle().flexWrap() != YGNode().getStyle().flexWrap()) {
      appendFormatedString(
          str, "flex-wrap: %s; ", YGWrapToString(node->getStyle().flexWrap()));
    }

    if (node->getStyle().overflow() != YGNode().getStyle().overflow()) {
      appendFormatedString(
          str,
          "overflow: %s; ",
          YGOverflowToString(node->getStyle().overflow()));
    }

    if (node->getStyle().display() != YGNode().getStyle().display()) {
      appendFormatedString(
          str, "display: %s; ", YGDisplayToString(node->getStyle().display()));
    }
    appendEdges(str, "margin", node->getStyle().margin());
    appendEdges(str, "padding", node->getStyle().padding());
    appendEdges(str, "border", node->getStyle().border());

    appendNumberIfNotAuto(
        str, "width", node->getStyle().dimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(
        str, "height", node->getStyle().dimensions()[YGDimensionHeight]);
    appendNumberIfNotAuto(
        str, "max-width", node->getStyle().maxDimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(
        str, "max-height", node->getStyle().maxDimensions()[YGDimensionHeight]);
    appendNumberIfNotAuto(
        str, "min-width", node->getStyle().minDimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(
        str, "min-height", node->getStyle().minDimensions()[YGDimensionHeight]);

    if (node->getStyle().positionType() != YGNode().getStyle().positionType()) {
      appendFormatedString(
          str,
          "position: %s; ",
          YGPositionTypeToString(node->getStyle().positionType()));
    }

    appendEdgeIfNotUndefined(
        str, "left", node->getStyle().position(), YGEdgeLeft);
    appendEdgeIfNotUndefined(
        str, "right", node->getStyle().position(), YGEdgeRight);
    appendEdgeIfNotUndefined(
        str, "top", node->getStyle().position(), YGEdgeTop);
    appendEdgeIfNotUndefined(
        str, "bottom", node->getStyle().position(), YGEdgeBottom);
    appendFormatedString(str, "\" ");

    if (node->hasMeasureFunc()) {
      appendFormatedString(str, "has-custom-measure=\"true\"");
    }
  }
  appendFormatedString(str, ">");

  const uint32_t childCount = static_cast<uint32_t>(node->getChildren().size());
  if (options & YGPrintOptionsChildren && childCount > 0) {
    for (uint32_t i = 0; i < childCount; i++) {
      appendFormatedString(str, "\n");
      YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
    }
    appendFormatedString(str, "\n");
    indent(str, level);
  }
  appendFormatedString(str, "
");
}
} // namespace yoga
} // namespace facebook
#endif
<commit_msg>`YGNodeToString`: take const ref to node style<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree.
 */
#ifdef DEBUG
#include "YGNodePrint.h"
#include <stdarg.h>
#include "YGEnums.h"
#include "YGNode.h"
#include "Yoga-internal.h"
#include "Utils.h"

namespace facebook {
namespace yoga {
typedef std::string string;

static void indent(string& base, uint32_t level) {
  for (uint32_t i = 0; i < level; ++i) {
    base.append("  ");
  }
}

static bool areFourValuesEqual(const YGStyle::Edges& four) {
  return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
      YGValueEqual(four[0], four[3]);
}

static void appendFormatedString(string& str, const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  va_list argsCopy;
  va_copy(argsCopy, args);
  std::vector<char> buf(1 + vsnprintf(NULL, 0, fmt, args));
  va_end(args);
  vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
  va_end(argsCopy);
  string result = string(buf.begin(), buf.end() - 1);
  str.append(result);
}

static void appendFloatOptionalIfDefined(
    string& base,
    const string key,
    const YGFloatOptional num) {
  if (!num.isUndefined()) {
    appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap());
  }
}

static void appendNumberIfNotUndefined(
    string& base,
    const string key,
    const YGValue number) {
  if (number.unit != YGUnitUndefined) {
    if (number.unit == YGUnitAuto) {
      base.append(key + ": auto; ");
    } else {
      string unit = number.unit == YGUnitPoint ? "px" : "%%";
      appendFormatedString(
          base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str());
    }
  }
}

static void appendNumberIfNotAuto(
    string& base,
    const string& key,
    const YGValue number) {
  if (number.unit != YGUnitAuto) {
    appendNumberIfNotUndefined(base, key, number);
  }
}

static void appendNumberIfNotZero(
    string& base,
    const string& str,
    const YGValue number) {
  if (number.unit == YGUnitAuto) {
    base.append(str + ": auto; ");
  } else if (!YGFloatsEqual(number.value, 0)) {
    appendNumberIfNotUndefined(base, str, number);
  }
}

static void appendEdges(
    string& base,
    const string& key,
    const YGStyle::Edges& edges) {
  if (areFourValuesEqual(edges)) {
    appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
  } else {
    for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
      string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
      appendNumberIfNotZero(base, str, edges[edge]);
    }
  }
}

static void appendEdgeIfNotUndefined(
    string& base,
    const string& str,
    const YGStyle::Edges& edges,
    const YGEdge edge) {
  appendNumberIfNotUndefined(
      base,
      str,
      YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined()));
}

void YGNodeToString(
    std::string& str,
    YGNodeRef node,
    YGPrintOptions options,
    uint32_t level) {
  indent(str, level);
  appendFormatedString(str, "
getLayout().dimensions[YGDimensionWidth]);
    appendFormatedString(
        str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]);
    appendFormatedString(
        str, "top: %g; ", node->getLayout().position[YGEdgeTop]);
    appendFormatedString(
        str, "left: %g;", node->getLayout().position[YGEdgeLeft]);
    appendFormatedString(str, "\" ");
  }

  if (options & YGPrintOptionsStyle) {
    appendFormatedString(str, "style=\"");
    const auto& style = node->getStyle();
    if (style.flexDirection() != YGNode().getStyle().flexDirection()) {
      appendFormatedString(
          str,
          "flex-direction: %s; ",
          YGFlexDirectionToString(style.flexDirection()));
    }
    if (style.justifyContent() != YGNode().getStyle().justifyContent()) {
      appendFormatedString(
          str,
          "justify-content: %s; ",
          YGJustifyToString(style.justifyContent()));
    }
    if (style.alignItems() != YGNode().getStyle().alignItems()) {
      appendFormatedString(
          str, "align-items: %s; ", YGAlignToString(style.alignItems()));
    }
    if (style.alignContent() != YGNode().getStyle().alignContent()) {
      appendFormatedString(
          str, "align-content: %s; ", YGAlignToString(style.alignContent()));
    }
    if (style.alignSelf() != YGNode().getStyle().alignSelf()) {
      appendFormatedString(
          str, "align-self: %s; ", YGAlignToString(style.alignSelf()));
    }
    appendFloatOptionalIfDefined(str, "flex-grow", style.flexGrow());
    appendFloatOptionalIfDefined(str, "flex-shrink", style.flexShrink());
    appendNumberIfNotAuto(str, "flex-basis", style.flexBasis());
    appendFloatOptionalIfDefined(str, "flex", style.flex());

    if (style.flexWrap() != YGNode().getStyle().flexWrap()) {
      appendFormatedString(
          str, "flex-wrap: %s; ", YGWrapToString(style.flexWrap()));
    }

    if (style.overflow() != YGNode().getStyle().overflow()) {
      appendFormatedString(
          str, "overflow: %s; ", YGOverflowToString(style.overflow()));
    }

    if (style.display() != YGNode().getStyle().display()) {
      appendFormatedString(
          str, "display: %s; ", YGDisplayToString(style.display()));
    }
    appendEdges(str, "margin", style.margin());
    appendEdges(str, "padding", style.padding());
    appendEdges(str, "border", style.border());

    appendNumberIfNotAuto(str, "width", style.dimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(str, "height", style.dimensions()[YGDimensionHeight]);
    appendNumberIfNotAuto(
        str, "max-width", style.maxDimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(
        str, "max-height", style.maxDimensions()[YGDimensionHeight]);
    appendNumberIfNotAuto(
        str, "min-width", style.minDimensions()[YGDimensionWidth]);
    appendNumberIfNotAuto(
        str, "min-height", style.minDimensions()[YGDimensionHeight]);

    if (style.positionType() != YGNode().getStyle().positionType()) {
      appendFormatedString(
          str, "position: %s; ", YGPositionTypeToString(style.positionType()));
    }

    appendEdgeIfNotUndefined(str, "left", style.position(), YGEdgeLeft);
    appendEdgeIfNotUndefined(str, "right", style.position(), YGEdgeRight);
    appendEdgeIfNotUndefined(str, "top", style.position(), YGEdgeTop);
    appendEdgeIfNotUndefined(str, "bottom", style.position(), YGEdgeBottom);
    appendFormatedString(str, "\" ");

    if (node->hasMeasureFunc()) {
      appendFormatedString(str, "has-custom-measure=\"true\"");
    }
  }
  appendFormatedString(str, ">");

  const uint32_t childCount = static_cast<uint32_t>(node->getChildren().size());
  if (options & YGPrintOptionsChildren && childCount > 0) {
    for (uint32_t i = 0; i < childCount; i++) {
      appendFormatedString(str, "\n");
      YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
    }
    appendFormatedString(str, "\n");
    indent(str, level);
  }
  appendFormatedString(str, "
");
}
} // namespace yoga
} // namespace facebook
#endif
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*   Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */

//win32

#pragma warning(disable: 4201)

#include "avmshell.h"
#include "WinFile.h"
#include <Mmsystem.h>

namespace avmshell
{
	class WinPlatform : public Platform
	{
	public:

		virtual ~WinPlatform(){}

		virtual void exit(int code);

		virtual File* createFile();
		virtual void destroyFile(File* file);

		virtual void initializeLogging(const char* filename);

		virtual int logMessage(const char* message);
		virtual char* getUserInput(char* buffer, int bufferSize);

		virtual void setTimer(int seconds, AvmTimerCallback callback, void* callbackData);
		virtual uintptr_t getStackBase();
	};

	struct TimerCallbackInfo
	{
		AvmTimerCallback callbackFunc;
		void* userData;
	};

	void CALLBACK TimeoutProc(UINT /*uTimerID*/,
							  UINT /*uMsg*/,
							  DWORD_PTR dwUser,
							  DWORD_PTR /*dw1*/,
							  DWORD_PTR /*dw2*/)
	{
		TimerCallbackInfo* info = (TimerCallbackInfo*)dwUser;
		info->callbackFunc(info->userData);
		delete info;
	}

	void WinPlatform::exit(int code)
	{
		::exit(code);
	}

	File* WinPlatform::createFile()
	{
		return new WinFile();
	}

	void WinPlatform::destroyFile(File* file)
	{
		delete file;
	}

	int WinPlatform::logMessage(const char* message)
	{
		return fprintf(stdout, message);
	}

	char* WinPlatform::getUserInput(char* buffer, int bufferSize)
	{
		fflush(stdout);
		fgets(buffer, bufferSize, stdin);
		return buffer;
	}

	void WinPlatform::setTimer(int seconds, AvmTimerCallback callback, void* callbackData)
	{
		TimerCallbackInfo* info = new TimerCallbackInfo;
		info->callbackFunc = callback;
		info->userData = callbackData;

		timeSetEvent(seconds*1000,
			seconds*1000,
			(LPTIMECALLBACK)TimeoutProc,
			(DWORD_PTR)info,
			TIME_ONESHOT);
	}

	uintptr_t WinPlatform::getStackBase()
	{
	#ifdef AVMPLUS_AMD64
		const int kStackMargin = 262144;
	#elif defined(UNDER_CE)
		const int kStackMargin = 16384;
	#else
		const int kStackMargin = 131072;
	#endif

		SYSTEM_INFO sysinfo;
		GetSystemInfo(&sysinfo);

		int dummy;
		uintptr_t sp = (uintptr_t)(&dummy);
		sp &= ~uintptr_t(sysinfo.dwPageSize-1);

		MEMORY_BASIC_INFORMATION buf;
		if (VirtualQuery((void*)sp, &buf, sizeof(buf)) == sizeof(buf)) {
			return (uintptr_t)buf.AllocationBase + kStackMargin;
		}

		return 0;
	}

	#if !defined (AVMPLUS_ARM)

		#include "dbghelp.h"

		extern bool show_error;

		unsigned long CrashFilter(LPEXCEPTION_POINTERS pException, int exceptionCode)
		{
			unsigned long result;
			if ((result = UnhandledExceptionFilter(pException)) != EXCEPTION_EXECUTE_HANDLER)
			{
				return result;
			}
			else if (avmshell::show_error)
			{
				// if -error option dont do a dump
				return EXCEPTION_CONTINUE_SEARCH;
			}

			AvmLog("avmplus crash: exception 0x%08lX occurred\n", exceptionCode);

			typedef BOOL (WINAPI *MINIDUMP_WRITE_DUMP)(
				HANDLE hProcess,
				DWORD ProcessId,
				HANDLE hFile,
				MINIDUMP_TYPE DumpType,
				PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
				PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
				PMINIDUMP_CALLBACK_INFORMATION CallbackParam
				);

			HMODULE hDbgHelp = LoadLibrary("dbghelp.dll");
			MINIDUMP_WRITE_DUMP MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp,
				"MiniDumpWriteDump");

			if (MiniDumpWriteDump_)
			{
				MINIDUMP_EXCEPTION_INFORMATION  M;
				const char DumpPath[] = "avmplusCrash.dmp";

				M.ThreadId = GetCurrentThreadId();
				M.ExceptionPointers = pException;
				M.ClientPointers = 0;

				AvmLog("Writing minidump crash log to %s\n", DumpPath);

				HANDLE hDumpFile = CreateFile(DumpPath, GENERIC_WRITE, 0,
					NULL, CREATE_ALWAYS,
					FILE_ATTRIBUTE_NORMAL, NULL);

				MiniDumpWriteDump_(GetCurrentProcess(),
					GetCurrentProcessId(),
					hDumpFile,
					MiniDumpNormal,
					(pException) ? &M : NULL, NULL, NULL);

				CloseHandle(hDumpFile);
			}
			else
			{
				AvmLog("minidump not available, no crash log written.\n");
			}

			return result;
		}
	#endif //!AVMPLUS_ARM

		void WinPlatform::initializeLogging(const char* filename)
		{
		#if defined (UNDER_CE)
			int filenameLen = VMPI_strlen(filename);

			TCHAR* logname = new TCHAR[filenameLen+1];

			int n = mbstowcs(logname, filename, filenameLen);

			_tcscpy(logname+n,_T(".log"));

			_wfreopen(logname, L"w", stdout);

			delete [] logname;
		#else
			FILE *f = freopen(filename, "w", stdout);
			if (!f)
				AvmLog("freopen %s failed.\n",filename);
		#endif /* UNDER_CE */
		}

} //namespace avmshell

avmshell::WinPlatform* gPlatformHandle = NULL;

avmshell::Platform* avmshell::Platform::GetInstance()
{
	AvmAssert(gPlatformHandle != NULL);
	return gPlatformHandle;
}

#if !defined (AVMPLUS_ARM)

	static int executeShell(int argc, char *argv[])
	{
		int code = 0;

		__try
		{
			code = avmshell::Shell::run(argc, argv);
		}
		__except(avmshell::CrashFilter(GetExceptionInformation(), GetExceptionCode()))
		{
			code = -1;
		}

		return code;
	}

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

		avmshell::WinPlatform platformInstance;
		gPlatformHandle = &platformInstance;

		int code = executeShell(argc, argv);

		return code;
	}

#endif /* !AVMPLUS_ARM */

#if defined (UNDER_CE)

	// TODO this is a hack until we learn how to determine stack top
	// in ARM
	int StackTop;

	int wmain(int argc, TCHAR *argv[])
	{
		int sp;
		StackTop = (int) &sp;

		avmshell::WinPlatform platformInstance;
		gPlatformHandle = &platformInstance;

		char** argArray = (char**) malloc(argc*sizeof(char*));
		for(int i=0;i<argc;++i)
		{
			int len = (wcslen(argv[i])+1) << 1;
			argArray[i] = (char*) malloc(len);
			wcstombs(argArray[i], argv[i], len);
		}
		int code = avmshell::Shell::run(argc, argArray);

		for(int i=0;i<argc;++i)
		{
			free(argArray[i]);
		}
		free(argArray);

		return code;
	}

#endif
<commit_msg>shell/avmshellWin.cpp: Fix for WinMobile to generate the correct log filename.  A bug in avmshellWin.cpp, introduced in changeset 1565, was appending an extra ?.log? resulting in the log file name to be [filename].log.log (change=rishit, r=stejohns)<commit_after>/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*   Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */

//win32

#pragma warning(disable: 4201)

#include "avmshell.h"
#include "WinFile.h"
#include <Mmsystem.h>

namespace avmshell
{
	class WinPlatform : public Platform
	{
	public:

		virtual ~WinPlatform(){}

		virtual void exit(int code);

		virtual File* createFile();
		virtual void destroyFile(File* file);

		virtual void initializeLogging(const char* filename);

		virtual int logMessage(const char* message);
		virtual char* getUserInput(char* buffer, int bufferSize);

		virtual void setTimer(int seconds, AvmTimerCallback callback, void* callbackData);
		virtual uintptr_t getStackBase();
	};

	struct TimerCallbackInfo
	{
		AvmTimerCallback callbackFunc;
		void* userData;
	};

	void CALLBACK TimeoutProc(UINT /*uTimerID*/,
							  UINT /*uMsg*/,
							  DWORD_PTR dwUser,
							  DWORD_PTR /*dw1*/,
							  DWORD_PTR /*dw2*/)
	{
		TimerCallbackInfo* info = (TimerCallbackInfo*)dwUser;
		info->callbackFunc(info->userData);
		delete info;
	}

	void WinPlatform::exit(int code)
	{
		::exit(code);
	}

	File* WinPlatform::createFile()
	{
		return new WinFile();
	}

	void WinPlatform::destroyFile(File* file)
	{
		delete file;
	}

	int WinPlatform::logMessage(const char* message)
	{
		return fprintf(stdout, message);
	}

	char* WinPlatform::getUserInput(char* buffer, int bufferSize)
	{
		fflush(stdout);
		fgets(buffer, bufferSize, stdin);
		return buffer;
	}

	void WinPlatform::setTimer(int seconds, AvmTimerCallback callback, void* callbackData)
	{
		TimerCallbackInfo* info = new TimerCallbackInfo;
		info->callbackFunc = callback;
		info->userData = callbackData;

		timeSetEvent(seconds*1000,
			seconds*1000,
			(LPTIMECALLBACK)TimeoutProc,
			(DWORD_PTR)info,
			TIME_ONESHOT);
	}

	uintptr_t WinPlatform::getStackBase()
	{
	#ifdef AVMPLUS_AMD64
		const int kStackMargin = 262144;
	#elif defined(UNDER_CE)
		const int kStackMargin = 16384;
	#else
		const int kStackMargin = 131072;
	#endif

		SYSTEM_INFO sysinfo;
		GetSystemInfo(&sysinfo);

		int dummy;
		uintptr_t sp = (uintptr_t)(&dummy);
		sp &= ~uintptr_t(sysinfo.dwPageSize-1);

		MEMORY_BASIC_INFORMATION buf;
		if (VirtualQuery((void*)sp, &buf, sizeof(buf)) == sizeof(buf)) {
			return (uintptr_t)buf.AllocationBase + kStackMargin;
		}

		return 0;
	}

	#if !defined (AVMPLUS_ARM)

		#include "dbghelp.h"

		extern bool show_error;

		unsigned long CrashFilter(LPEXCEPTION_POINTERS pException, int exceptionCode)
		{
			unsigned long result;
			if ((result = UnhandledExceptionFilter(pException)) != EXCEPTION_EXECUTE_HANDLER)
			{
				return result;
			}
			else if (avmshell::show_error)
			{
				// if -error option dont do a dump
				return EXCEPTION_CONTINUE_SEARCH;
			}

			AvmLog("avmplus crash: exception 0x%08lX occurred\n", exceptionCode);

			typedef BOOL (WINAPI *MINIDUMP_WRITE_DUMP)(
				HANDLE hProcess,
				DWORD ProcessId,
				HANDLE hFile,
				MINIDUMP_TYPE DumpType,
				PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
				PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
				PMINIDUMP_CALLBACK_INFORMATION CallbackParam
				);

			HMODULE hDbgHelp = LoadLibrary("dbghelp.dll");
			MINIDUMP_WRITE_DUMP MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp,
				"MiniDumpWriteDump");

			if (MiniDumpWriteDump_)
			{
				MINIDUMP_EXCEPTION_INFORMATION  M;
				const char DumpPath[] = "avmplusCrash.dmp";

				M.ThreadId = GetCurrentThreadId();
				M.ExceptionPointers = pException;
				M.ClientPointers = 0;

				AvmLog("Writing minidump crash log to %s\n", DumpPath);

				HANDLE hDumpFile = CreateFile(DumpPath, GENERIC_WRITE, 0,
					NULL, CREATE_ALWAYS,
					FILE_ATTRIBUTE_NORMAL, NULL);

				MiniDumpWriteDump_(GetCurrentProcess(),
					GetCurrentProcessId(),
					hDumpFile,
					MiniDumpNormal,
					(pException) ? &M : NULL, NULL, NULL);

				CloseHandle(hDumpFile);
			}
			else
			{
				AvmLog("minidump not available, no crash log written.\n");
			}

			return result;
		}
	#endif //!AVMPLUS_ARM

		void WinPlatform::initializeLogging(const char* filename)
		{
		#if defined (UNDER_CE)
			int filenameLen = VMPI_strlen(filename);

			TCHAR* logname = new TCHAR[filenameLen+1];

			mbstowcs(logname, filename, filenameLen+1);

			_wfreopen(logname, L"w", stdout);

			delete [] logname;
		#else
			FILE *f = freopen(filename, "w", stdout);
			if (!f)
				AvmLog("freopen %s failed.\n",filename);
		#endif /* UNDER_CE */
		}

} //namespace avmshell

avmshell::WinPlatform* gPlatformHandle = NULL;

avmshell::Platform* avmshell::Platform::GetInstance()
{
	AvmAssert(gPlatformHandle != NULL);
	return gPlatformHandle;
}

#if !defined (AVMPLUS_ARM)

	static int executeShell(int argc, char *argv[])
	{
		int code = 0;

		__try
		{
			code = avmshell::Shell::run(argc, argv);
		}
		__except(avmshell::CrashFilter(GetExceptionInformation(), GetExceptionCode()))
		{
			code = -1;
		}

		return code;
	}

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

		avmshell::WinPlatform platformInstance;
		gPlatformHandle = &platformInstance;

		int code = executeShell(argc, argv);

		return code;
	}

#endif /* !AVMPLUS_ARM */

#if defined (UNDER_CE)

	// TODO this is a hack until we learn how to determine stack top
	// in ARM
	int StackTop;

	int wmain(int argc, TCHAR *argv[])
	{
		int sp;
		StackTop = (int) &sp;

		avmshell::WinPlatform platformInstance;
		gPlatformHandle = &platformInstance;

		char** argArray = (char**) malloc(argc*sizeof(char*));
		for(int i=0;i<argc;++i)
		{
			int len = (wcslen(argv[i])+1) << 1;
			argArray[i] = (char*) malloc(len);
			wcstombs(argArray[i], argv[i], len);
		}
		int code = avmshell::Shell::run(argc, argArray);

		for(int i=0;i<argc;++i)
		{
			free(argArray[i]);
		}
		free(argArray);

		return code;
	}

#endif
<|endoftext|>


<commit_before>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * DMXTriggerTest.cpp
 * Test fixture for the DMXTrigger class.
 * Copyright (C) 2011 Simon Newton
 */

#include <cppunit/extensions/HelperMacros.h>
#include <ola/Logging.h>
#include <ola/DmxBuffer.h>
#include <vector>
#include "tools/ola_trigger/Action.h"
#include "tools/ola_trigger/DmxTrigger.h"
#include "tools/ola_trigger/MockAction.h"

using std::vector;
using ola::DmxBuffer;

class DMXTriggerTest: public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(DMXTriggerTest);
  CPPUNIT_TEST(testRisingEdgeTrigger);
  CPPUNIT_TEST(testFallingEdgeTrigger);
  CPPUNIT_TEST_SUITE_END();

  public:
    void testRisingEdgeTrigger();
    void testFallingEdgeTrigger();

    void setUp() {
      ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR);
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION(DMXTriggerTest);

/**
 * Check that triggering on a rising edge works correctly.
 */
void DMXTriggerTest::testRisingEdgeTrigger() {
  // setup the actions
  vector<Slot*> slots;
  Slot slot(2);
  MockAction *action = new MockAction();
  BadAction *bad_action = new BadAction();
  ValueInterval interval(10, 20);
  slot.AddAction(interval, action, bad_action);
  slots.push_back(&slot);

  Context context;
  DMXTrigger trigger(&context, slots);
  DmxBuffer buffer;

  // this shouldn't trigger
  buffer.SetFromString("0,0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // trigger rising edge
  buffer.SetFromString("0,0,10");
  trigger.NewDMX(buffer);
  action->CheckForValue(__LINE__, 10);

  // now send the same again
  CPPUNIT_ASSERT(action->NoCalls());
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // shorten the frame
  buffer.SetFromString("0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // lengthen again
  buffer.SetFromString("0,0,10,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // change everything else
  buffer.SetFromString("10,100,10,20");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());
}

/**
 * Test that falling edges trigger
 */
void DMXTriggerTest::testFallingEdgeTrigger() {
  // setup the actions
  vector<Slot*> slots;
  Slot slot(2);
  MockAction *rising_action = new MockAction();
  MockAction *falling_action = new MockAction();
  ValueInterval interval(10, 20);
  slot.AddAction(interval, rising_action, falling_action);
  slots.push_back(&slot);

  Context context;
  DMXTrigger trigger(&context, slots);
  DmxBuffer buffer;

  // trigger
  buffer.SetFromString("0,0,20");
  trigger.NewDMX(buffer);
  rising_action->CheckForValue(__LINE__, 20);
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // trigger a falling edge
  buffer.SetFromString("0,0,19");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  falling_action->CheckForValue(__LINE__, 19);

  // now send the same again
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // shorten the frame
  buffer.SetFromString("0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // lengthen again
  buffer.SetFromString("0,0,19,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // change everything else
  buffer.SetFromString("10,100,19,20");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // change once more
  buffer.SetFromString("10,100,20,20");
  trigger.NewDMX(buffer);
  rising_action->CheckForValue(__LINE__, 20);
  CPPUNIT_ASSERT(falling_action->NoCalls());
}
<commit_msg> * fix the include file<commit_after>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * DMXTriggerTest.cpp
 * Test fixture for the DMXTrigger class.
 * Copyright (C) 2011 Simon Newton
 */

#include <cppunit/extensions/HelperMacros.h>
#include <ola/Logging.h>
#include <ola/DmxBuffer.h>
#include <vector>
#include "tools/ola_trigger/Action.h"
#include "tools/ola_trigger/DMXTrigger.h"
#include "tools/ola_trigger/MockAction.h"

using std::vector;
using ola::DmxBuffer;

class DMXTriggerTest: public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(DMXTriggerTest);
  CPPUNIT_TEST(testRisingEdgeTrigger);
  CPPUNIT_TEST(testFallingEdgeTrigger);
  CPPUNIT_TEST_SUITE_END();

  public:
    void testRisingEdgeTrigger();
    void testFallingEdgeTrigger();

    void setUp() {
      ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR);
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION(DMXTriggerTest);

/**
 * Check that triggering on a rising edge works correctly.
 */
void DMXTriggerTest::testRisingEdgeTrigger() {
  // setup the actions
  vector<Slot*> slots;
  Slot slot(2);
  MockAction *action = new MockAction();
  BadAction *bad_action = new BadAction();
  ValueInterval interval(10, 20);
  slot.AddAction(interval, action, bad_action);
  slots.push_back(&slot);

  Context context;
  DMXTrigger trigger(&context, slots);
  DmxBuffer buffer;

  // this shouldn't trigger
  buffer.SetFromString("0,0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // trigger rising edge
  buffer.SetFromString("0,0,10");
  trigger.NewDMX(buffer);
  action->CheckForValue(__LINE__, 10);

  // now send the same again
  CPPUNIT_ASSERT(action->NoCalls());
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // shorten the frame
  buffer.SetFromString("0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // lengthen again
  buffer.SetFromString("0,0,10,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());

  // change everything else
  buffer.SetFromString("10,100,10,20");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(action->NoCalls());
}

/**
 * Test that falling edges trigger
 */
void DMXTriggerTest::testFallingEdgeTrigger() {
  // setup the actions
  vector<Slot*> slots;
  Slot slot(2);
  MockAction *rising_action = new MockAction();
  MockAction *falling_action = new MockAction();
  ValueInterval interval(10, 20);
  slot.AddAction(interval, rising_action, falling_action);
  slots.push_back(&slot);

  Context context;
  DMXTrigger trigger(&context, slots);
  DmxBuffer buffer;

  // trigger
  buffer.SetFromString("0,0,20");
  trigger.NewDMX(buffer);
  rising_action->CheckForValue(__LINE__, 20);
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // trigger a falling edge
  buffer.SetFromString("0,0,19");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  falling_action->CheckForValue(__LINE__, 19);

  // now send the same again
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // shorten the frame
  buffer.SetFromString("0,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // lengthen again
  buffer.SetFromString("0,0,19,0");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // change everything else
  buffer.SetFromString("10,100,19,20");
  trigger.NewDMX(buffer);
  CPPUNIT_ASSERT(rising_action->NoCalls());
  CPPUNIT_ASSERT(falling_action->NoCalls());

  // change once more
  buffer.SetFromString("10,100,20,20");
  trigger.NewDMX(buffer);
  rising_action->CheckForValue(__LINE__, 20);
  CPPUNIT_ASSERT(falling_action->NoCalls());
}
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// 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 "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/FrameworkConvert.h"
#include "SurgSim/Framework/PoseComponent.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/SceneElement.h"
#include "SurgSim/Math/MathConvert.h"
#include "SurgSim/Math/MeshShape.h"
#include "SurgSim/Math/Valid.h"
#include "SurgSim/Physics/Localization.h"
#include "SurgSim/Physics/RigidCollisionRepresentation.h"
#include "SurgSim/Physics/RigidRepresentationBase.h"
#include "SurgSim/Physics/RigidRepresentationLocalization.h"
#include "SurgSim/Physics/PhysicsConvert.h"

namespace SurgSim
{
namespace Physics
{

RigidRepresentationBase::RigidRepresentationBase(const std::string& name) :
	Representation(name),
	m_parametersValid(false),
	m_rho(0.0),
	m_mass(std::numeric_limits<double>::quiet_NaN()),
	m_linearDamping(0.0),
	m_angularDamping(0.0)
{
	m_localInertia.setConstant(std::numeric_limits<double>::quiet_NaN());

	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, RigidRepresentationState,
									  RigidRepresentationState, getInitialState, setInitialState);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, std::shared_ptr<SurgSim::Collision::Representation>,
									  CollisionRepresentation, getCollisionRepresentation, setCollisionRepresentation);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, Density, getDensity, setDensity);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, LinearDamping,
									  getLinearDamping, setLinearDamping);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, AngularDamping,
									  getAngularDamping, setAngularDamping);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, std::shared_ptr<SurgSim::Math::Shape>, Shape,
									  getShape, setShape);

}

RigidRepresentationBase::~RigidRepresentationBase()
{
}

bool RigidRepresentationBase::doInitialize()
{
	if (m_shape != nullptr)
	{
		SURGSIM_ASSERT(m_shape->isValid()) <<
			"An invalid shape is used in this RigidRepresentationBase.";
	}

	return true;
}

bool RigidRepresentationBase::doWakeUp()
{
	m_initialState.setPose(getPose());
	m_currentState = m_initialState;
	m_finalState = m_initialState;
	m_previousState = m_initialState;
	updateGlobalInertiaMatrices(m_currentState);

	return true;
}

void RigidRepresentationBase::setInitialState(const RigidRepresentationState& state)
{
	m_initialState = state;
	m_currentState = state;
	m_previousState = state;

	updateGlobalInertiaMatrices(m_currentState);
}

void RigidRepresentationBase::resetState()
{
	Representation::resetState();

	m_currentState  = m_initialState;
	m_previousState = m_initialState;
	m_finalState    = m_initialState;

	updateGlobalInertiaMatrices(m_currentState);
}

const RigidRepresentationState& RigidRepresentationBase::getInitialState() const
{
	return m_initialState;
}

const RigidRepresentationState& RigidRepresentationBase::getCurrentState() const
{
	return m_currentState;
}

const RigidRepresentationState& RigidRepresentationBase::getPreviousState() const
{
	return m_previousState;
}

std::shared_ptr<Localization> RigidRepresentationBase::createLocalization(
	const SurgSim::DataStructures::Location& location)
{
	return std::move(createTypedLocalization<RigidRepresentationLocalization>(location));
}

void RigidRepresentationBase::setDensity(double rho)
{
	m_rho = rho;
	updateProperties();
}

double RigidRepresentationBase::getDensity() const
{
	return m_rho;
}

double RigidRepresentationBase::getMass() const
{
	return m_mass;
}

const SurgSim::Math::Vector3d& RigidRepresentationBase::getMassCenter() const
{
	return m_massCenter;
}

const SurgSim::Math::Matrix33d& RigidRepresentationBase::getLocalInertia() const
{
	return m_localInertia;
}

void RigidRepresentationBase::setLinearDamping(double linearDamping)
{
	m_linearDamping = linearDamping;
}

double RigidRepresentationBase::getLinearDamping() const
{
	return m_linearDamping;
}

void RigidRepresentationBase::setAngularDamping(double angularDamping)
{
	m_angularDamping = angularDamping;
}

double RigidRepresentationBase::getAngularDamping() const
{
	return m_angularDamping;
}

void RigidRepresentationBase::setShape(const std::shared_ptr<SurgSim::Math::Shape> shape)
{
	m_shape = shape;
	if (shape != nullptr)
	{
		updateProperties();
	}
}

const std::shared_ptr<SurgSim::Math::Shape> RigidRepresentationBase::getShape() const
{
	return m_shape;
}

void RigidRepresentationBase::updateProperties()
{
	if (m_shape != nullptr)
	{
		SURGSIM_ASSERT(m_shape->isValid()) << "Invalid shape.";
		m_mass         = m_rho * m_shape->getVolume();
		m_massCenter   = m_shape->getCenter();
		m_localInertia = m_rho * m_shape->getSecondMomentOfVolume();
		m_parametersValid = m_rho > 0.0 &&
			SurgSim::Math::isValid(m_localInertia) &&
			!m_localInertia.isZero() &&
			m_localInertia.diagonal().minCoeff() > 0.0 &&
			SurgSim::Math::isValid(m_mass) && m_mass > 0.0;
	}
}

void SurgSim::Physics::RigidRepresentationBase::beforeUpdate(double dt)
{
	m_previousState = m_currentState;
}

void SurgSim::Physics::RigidRepresentationBase::afterUpdate(double dt)
{
	m_finalState = m_currentState;
	driveSceneElementPose(m_finalState.getPose() * getLocalPose().inverse());
}

void RigidRepresentationBase::setCollisionRepresentation(
	std::shared_ptr<SurgSim::Collision::Representation> representation)
{
	if (m_collisionRepresentation != representation)
	{
		// If we have an old collision representation clear the dependency
		auto oldCollisionRep = std::dynamic_pointer_cast<RigidCollisionRepresentation>(m_collisionRepresentation);
		if (oldCollisionRep != nullptr)
		{
			oldCollisionRep->setRigidRepresentation(nullptr);
		}

		Representation::setCollisionRepresentation(representation);

		// If its a RigidCollisionRepresentation connect with this representation
		auto newCollisionRep = std::dynamic_pointer_cast<RigidCollisionRepresentation>(representation);
		if (newCollisionRep != nullptr)
		{
			newCollisionRep->setRigidRepresentation(std::static_pointer_cast<RigidRepresentationBase>(getSharedPtr()));
		}
	}
}

}; // Physics
}; // SurgSim
<commit_msg>Check if density is > 0 when updating Rigid's properties<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// 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 "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/FrameworkConvert.h"
#include "SurgSim/Framework/PoseComponent.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/SceneElement.h"
#include "SurgSim/Math/MathConvert.h"
#include "SurgSim/Math/MeshShape.h"
#include "SurgSim/Math/Valid.h"
#include "SurgSim/Physics/Localization.h"
#include "SurgSim/Physics/RigidCollisionRepresentation.h"
#include "SurgSim/Physics/RigidRepresentationBase.h"
#include "SurgSim/Physics/RigidRepresentationLocalization.h"
#include "SurgSim/Physics/PhysicsConvert.h"

namespace SurgSim
{
namespace Physics
{

RigidRepresentationBase::RigidRepresentationBase(const std::string& name) :
	Representation(name),
	m_parametersValid(false),
	m_rho(0.0),
	m_mass(std::numeric_limits<double>::quiet_NaN()),
	m_linearDamping(0.0),
	m_angularDamping(0.0)
{
	m_localInertia.setConstant(std::numeric_limits<double>::quiet_NaN());

	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, RigidRepresentationState,
									  RigidRepresentationState, getInitialState, setInitialState);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, std::shared_ptr<SurgSim::Collision::Representation>,
									  CollisionRepresentation, getCollisionRepresentation, setCollisionRepresentation);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, Density, getDensity, setDensity);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, LinearDamping,
									  getLinearDamping, setLinearDamping);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, double, AngularDamping,
									  getAngularDamping, setAngularDamping);
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(RigidRepresentationBase, std::shared_ptr<SurgSim::Math::Shape>, Shape,
									  getShape, setShape);

}

RigidRepresentationBase::~RigidRepresentationBase()
{
}

bool RigidRepresentationBase::doInitialize()
{
	if (m_shape != nullptr)
	{
		SURGSIM_ASSERT(m_shape->isValid()) <<
			"An invalid shape is used in this RigidRepresentationBase.";
	}

	return true;
}

bool RigidRepresentationBase::doWakeUp()
{
	m_initialState.setPose(getPose());
	m_currentState = m_initialState;
	m_finalState = m_initialState;
	m_previousState = m_initialState;
	updateGlobalInertiaMatrices(m_currentState);

	return true;
}

void RigidRepresentationBase::setInitialState(const RigidRepresentationState& state)
{
	m_initialState = state;
	m_currentState = state;
	m_previousState = state;

	updateGlobalInertiaMatrices(m_currentState);
}

void RigidRepresentationBase::resetState()
{
	Representation::resetState();

	m_currentState  = m_initialState;
	m_previousState = m_initialState;
	m_finalState    = m_initialState;

	updateGlobalInertiaMatrices(m_currentState);
}

const RigidRepresentationState& RigidRepresentationBase::getInitialState() const
{
	return m_initialState;
}

const RigidRepresentationState& RigidRepresentationBase::getCurrentState() const
{
	return m_currentState;
}

const RigidRepresentationState& RigidRepresentationBase::getPreviousState() const
{
	return m_previousState;
}

std::shared_ptr<Localization> RigidRepresentationBase::createLocalization(
	const SurgSim::DataStructures::Location& location)
{
	return std::move(createTypedLocalization<RigidRepresentationLocalization>(location));
}

void RigidRepresentationBase::setDensity(double rho)
{
	m_rho = rho;
	updateProperties();
}

double RigidRepresentationBase::getDensity() const
{
	return m_rho;
}

double RigidRepresentationBase::getMass() const
{
	return m_mass;
}

const SurgSim::Math::Vector3d& RigidRepresentationBase::getMassCenter() const
{
	return m_massCenter;
}

const SurgSim::Math::Matrix33d& RigidRepresentationBase::getLocalInertia() const
{
	return m_localInertia;
}

void RigidRepresentationBase::setLinearDamping(double linearDamping)
{
	m_linearDamping = linearDamping;
}

double RigidRepresentationBase::getLinearDamping() const
{
	return m_linearDamping;
}

void RigidRepresentationBase::setAngularDamping(double angularDamping)
{
	m_angularDamping = angularDamping;
}

double RigidRepresentationBase::getAngularDamping() const
{
	return m_angularDamping;
}

void RigidRepresentationBase::setShape(const std::shared_ptr<SurgSim::Math::Shape> shape)
{
	m_shape = shape;
	if (shape != nullptr)
	{
		updateProperties();
	}
}

const std::shared_ptr<SurgSim::Math::Shape> RigidRepresentationBase::getShape() const
{
	return m_shape;
}

void RigidRepresentationBase::updateProperties()
{
	if (m_shape != nullptr)
	{
		SURGSIM_ASSERT(m_shape->isValid()) << "Invalid shape.";
		if (m_rho > 0)
		{
			m_mass         = m_rho * m_shape->getVolume();
			m_massCenter   = m_shape->getCenter();
			m_localInertia = m_rho * m_shape->getSecondMomentOfVolume();
			m_parametersValid = m_rho > 0.0 &&
				SurgSim::Math::isValid(m_localInertia) &&
				!m_localInertia.isZero() &&
				m_localInertia.diagonal().minCoeff() > 0.0 &&
				SurgSim::Math::isValid(m_mass) && m_mass > 0.0;
		}
	}
}

void SurgSim::Physics::RigidRepresentationBase::beforeUpdate(double dt)
{
	m_previousState = m_currentState;
}

void SurgSim::Physics::RigidRepresentationBase::afterUpdate(double dt)
{
	m_finalState = m_currentState;
	driveSceneElementPose(m_finalState.getPose() * getLocalPose().inverse());
}

void RigidRepresentationBase::setCollisionRepresentation(
	std::shared_ptr<SurgSim::Collision::Representation> representation)
{
	if (m_collisionRepresentation != representation)
	{
		// If we have an old collision representation clear the dependency
		auto oldCollisionRep = std::dynamic_pointer_cast<RigidCollisionRepresentation>(m_collisionRepresentation);
		if (oldCollisionRep != nullptr)
		{
			oldCollisionRep->setRigidRepresentation(nullptr);
		}

		Representation::setCollisionRepresentation(representation);

		// If its a RigidCollisionRepresentation connect with this representation
		auto newCollisionRep = std::dynamic_pointer_cast<RigidCollisionRepresentation>(representation);
		if (newCollisionRep != nullptr)
		{
			newCollisionRep->setRigidRepresentation(std::static_pointer_cast<RigidRepresentationBase>(getSharedPtr()));
		}
	}
}

}; // Physics
}; // SurgSim
<|endoftext|>