├── deps ├── clear.sh └── fetch_and_build.sh ├── .gitignore ├── examples ├── logo.png ├── CMakeLists.txt ├── SDLMain.h ├── Demo.js └── Demo.cpp ├── tests ├── tut │ ├── tut_config.hpp │ ├── tut_reporter.hpp │ ├── tut_macros.hpp │ ├── tut_main.hpp │ ├── tut_result.hpp │ ├── tut_exception.hpp │ ├── tut_fpt.hpp │ ├── tut_console_reporter.hpp │ ├── tut_assert.hpp │ ├── tut_cppunit_reporter.hpp │ ├── tut_runner.hpp │ ├── tut_restartable.hpp │ └── tut_xml_reporter.hpp ├── CMakeLists.txt ├── Main.cpp ├── ColorParserTest.cpp └── CanvasTest.cpp ├── Makefile ├── src ├── CMakeLists.txt ├── util │ ├── ScopedLock.cpp │ ├── ScopedLock.h │ ├── Mutex.h │ ├── Mutex.cpp │ ├── Thread.cpp │ ├── Thread.h │ ├── Timer.mm │ ├── Timer.h │ └── Timer.cpp ├── binding │ ├── Types.h │ ├── Object.cpp │ ├── Attribute.h │ ├── TypeList.h │ ├── FunctionInfo.h │ ├── Object.h │ └── Translate.h ├── ColorParser.h ├── State.cpp ├── State.h ├── ImageData.h ├── ImageData.cpp ├── Script.h ├── Callback.h ├── Color.h ├── Painter.h ├── Context.h ├── Script.cpp ├── Canvas.cpp ├── ColorParser.cpp ├── Context.cpp └── Painter.cpp ├── LICENSE ├── CMakeLists.txt ├── include └── Canvas.h └── README.textile /deps/clear.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | cd `dirname $0` 4 | 5 | rm -rf skia 6 | rm -rf v8 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .waf* 2 | .lock-wscript 3 | .DS_Store 4 | build/ 5 | deps/skia 6 | deps/v8 -------------------------------------------------------------------------------- /examples/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wibbe/canvas-cpp/HEAD/examples/logo.png -------------------------------------------------------------------------------- /tests/tut/tut_config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_CONFIG_H_GUARD 2 | #define TUT_CONFIG_H_GUARD 3 | 4 | #define TUT_USE_RTTI 1 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /tests/tut/tut_reporter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_REPORTER 2 | #define TUT_REPORTER 3 | 4 | #include 5 | 6 | namespace tut 7 | { 8 | typedef console_reporter reporter; 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: compile 3 | 4 | configure: 5 | mkdir build 6 | (cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..) 7 | 8 | compile: 9 | make -C build 10 | 11 | run: 12 | (./build/bin/demo -i examples/logo.png examples/Demo.js) 13 | 14 | test: 15 | (cd build/bin && ./unit_test) 16 | 17 | clean: 18 | make -C build clean 19 | 20 | distclean: 21 | (rm -rf build) -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | SET(SOURCE 3 | CanvasTest.cpp 4 | ColorParserTest.cpp 5 | Main.cpp 6 | ) 7 | 8 | SET(LIBRARIES 9 | canvas 10 | skia 11 | v8 12 | ) 13 | 14 | IF(APPLE) 15 | LIST(APPEND LIBRARIES ${Carbon_FRAMEWORK}) 16 | LIST(APPEND LIBRARIES ${Cocoa_FRAMEWORK}) 17 | ENDIF() 18 | 19 | ADD_EXECUTABLE(unit_test ${SOURCE}) 20 | TARGET_LINK_LIBRARIES(unit_test ${LIBRARIES}) -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | SET(SOURCE 3 | Demo.cpp 4 | ) 5 | 6 | SET(LIBRARIES 7 | canvas 8 | skia 9 | v8 10 | ${SDL_LIBRARY} 11 | ${SDLIMAGE_LIBRARY} 12 | ) 13 | 14 | IF(APPLE) 15 | LIST(APPEND SOURCE SDLMain.m) 16 | LIST(APPEND LIBRARIES ${Carbon_FRAMEWORK}) 17 | LIST(APPEND LIBRARIES ${Cocoa_FRAMEWORK}) 18 | ENDIF() 19 | 20 | ADD_EXECUTABLE(demo ${SOURCE}) 21 | TARGET_LINK_LIBRARIES(demo ${LIBRARIES}) -------------------------------------------------------------------------------- /examples/SDLMain.h: -------------------------------------------------------------------------------- 1 | /* SDLMain.m - main entry point for our Cocoa-ized SDL app 2 | Initial Version: Darrell Walisser 3 | Non-NIB-Code & other changes: Max Horn 4 | 5 | Feel free to customize this file to suit your needs 6 | */ 7 | 8 | #ifndef _SDLMain_h_ 9 | #define _SDLMain_h_ 10 | 11 | #import 12 | 13 | @interface SDLMain : NSObject 14 | @end 15 | 16 | #endif /* _SDLMain_h_ */ 17 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | SET(SOURCE 3 | Canvas.cpp 4 | ColorParser.cpp 5 | Context.cpp 6 | Painter.cpp 7 | Script.cpp 8 | State.cpp 9 | ImageData.cpp 10 | util/Mutex.cpp 11 | util/ScopedLock.cpp 12 | util/Thread.cpp 13 | binding/Object.cpp 14 | ) 15 | 16 | SET(LIBRARIES 17 | skia 18 | v8 19 | ) 20 | 21 | IF(APPLE) 22 | LIST(APPEND SOURCE util/Timer.mm) 23 | ELSE() 24 | LIST(APPEND SOURCE util/Timer.cpp) 25 | ENDIF() 26 | 27 | ADD_LIBRARY(canvas ${SOURCE}) 28 | TARGET_LINK_LIBRARIES(canvas ${LIBRARIES}) 29 | 30 | -------------------------------------------------------------------------------- /deps/fetch_and_build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | cd `dirname $0` 4 | platform=`uname` 5 | 6 | echo "Fetching Skia..." 7 | svn checkout -r 614 http://skia.googlecode.com/svn/trunk/ skia 8 | 9 | cd skia 10 | if [ $platform -eq 'darwin' ] ; then 11 | echo "Building Skia for mac..." 12 | make SKIA_BUILD_FOR=mac SKIA_DEBUG=true 13 | else 14 | echo "Building Skia for linux..." 15 | make SKIA_DEBUG=true 16 | fi 17 | 18 | cd .. 19 | 20 | echo "Fetching V8..." 21 | svn checkout -r 5700 http://v8.googlecode.com/svn/trunk/ v8 22 | 23 | cd v8 24 | echo "Building V8..." 25 | scons mode=debug library=static snapshot=off -j4 26 | 27 | if [ $platform -eq 'Linux' ] ; then 28 | mv libv8_g.a libv8.a 29 | fi 30 | -------------------------------------------------------------------------------- /examples/Demo.js: -------------------------------------------------------------------------------- 1 | 2 | (function() { 3 | console.log("Starting Demo..."); 4 | 5 | var ctx = window.getContext('2d'); 6 | var img = window.getImage("examples/logo.png"); 7 | 8 | if (ctx && img) 9 | window.setInterval(paint, 50); // paint in 20Hz 10 | 11 | function paint() { 12 | ctx.clear(); 13 | ctx.fillStyle = 'rgb(255, 100, 50)'; 14 | ctx.globalAlpha = 0.5; 15 | ctx.fillRect(10, 10, 100, 100); 16 | 17 | ctx.drawImage(img, 120, 10); 18 | ctx.drawImage(img, 120, 74, 64, 32); 19 | 20 | ctx.beginPath(); 21 | ctx.moveTo(200, 200); 22 | ctx.lineTo(300, 200); 23 | ctx.quadraticCurveTo(300, 300, 200, 300); 24 | 25 | ctx.rect(700, 10, 90, 90); 26 | 27 | ctx.closePath(); 28 | 29 | ctx.strokeStyle = 'white'; 30 | ctx.lineWidth = 10.0; 31 | ctx.lineCap = 'round'; 32 | ctx.stroke(); 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Daniel Wiberg 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /tests/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace tut 7 | { 8 | test_runner_singleton runner; 9 | } 10 | 11 | class outbuf : public std::streambuf 12 | { 13 | public: 14 | outbuf() 15 | { 16 | setp(0, 0); 17 | } 18 | 19 | virtual int_type overflow(int_type c = traits_type::eof()) 20 | { 21 | return c; 22 | } 23 | }; 24 | 25 | int main(int argc, const char* argv[]) 26 | { 27 | tut::console_reporter reporter; 28 | tut::runner.get().set_callback(&reporter); 29 | 30 | // Redirect std::cerr so we don't print anything while running tests 31 | outbuf ob; 32 | std::streambuf *sb = std::cerr.rdbuf(&ob); 33 | 34 | try 35 | { 36 | if(tut::tut_main(argc, argv)) 37 | { 38 | std::cerr.rdbuf(sb); 39 | if(reporter.all_ok()) 40 | { 41 | return 0; 42 | } 43 | else 44 | { 45 | std::cerr << "\nUnit test failed!" << std::endl; 46 | } 47 | } 48 | } 49 | catch(const tut::no_such_group &ex) 50 | { 51 | std::cerr << "No such group: " << ex.what() << std::endl; 52 | } 53 | catch(const tut::no_such_test &ex) 54 | { 55 | std::cerr << "No such test: " << ex.what() << std::endl; 56 | } 57 | catch(const tut::tut_error &ex) 58 | { 59 | std::cout << "General error: " << ex.what() << std::endl; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/util/ScopedLock.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "util/ScopedLock.h" 24 | 25 | namespace canvas 26 | { 27 | 28 | ScopedLock::ScopedLock(Mutex & mutex) 29 | : m_mutex(mutex) 30 | { 31 | m_mutex.lock(); 32 | } 33 | 34 | ScopedLock::~ScopedLock() 35 | { 36 | m_mutex.unlock(); 37 | } 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/util/ScopedLock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_SCOPED_LOCK_HEADER 24 | #define CANVAS_SCOPED_LOCK_HEADER 25 | 26 | #include "util/Mutex.h" 27 | 28 | namespace canvas 29 | { 30 | class ScopedLock 31 | { 32 | public: 33 | ScopedLock(Mutex & mutex); 34 | ~ScopedLock(); 35 | 36 | private: 37 | Mutex & m_mutex; 38 | }; 39 | } 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /src/util/Mutex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_MUTEX_HEADER 24 | #define CANVAS_MUTEX_HEADER 25 | 26 | #include 27 | 28 | namespace canvas 29 | { 30 | class Mutex 31 | { 32 | public: 33 | Mutex(); 34 | ~Mutex(); 35 | 36 | void lock(); 37 | void unlock(); 38 | 39 | private: 40 | pthread_mutex_t m_mutex; 41 | }; 42 | } 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /src/util/Mutex.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "util/Mutex.h" 24 | 25 | namespace canvas 26 | { 27 | 28 | Mutex::Mutex() 29 | { 30 | pthread_mutex_init(&m_mutex, 0); 31 | } 32 | 33 | Mutex::~Mutex() 34 | { 35 | pthread_mutex_destroy(&m_mutex); 36 | } 37 | 38 | void Mutex::lock() 39 | { 40 | pthread_mutex_lock(&m_mutex); 41 | } 42 | 43 | void Mutex::unlock() 44 | { 45 | pthread_mutex_unlock(&m_mutex); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/binding/Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | #ifndef V8_SCRIPT_TYPES_HPP 23 | #define V8_SCRIPT_TYPES_HPP 24 | 25 | /** 26 | * Servs as a null marker for types. 27 | */ 28 | class NullType { }; 29 | 30 | /** 31 | * Serves as a default ("don't care") type for templates. 32 | */ 33 | struct EmptyType { }; 34 | 35 | /** 36 | * Class that generates a distinct type for each distinct constant 37 | * integral value passed. 38 | */ 39 | template 40 | struct Int2Type 41 | { 42 | enum { value = v }; 43 | }; 44 | 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /src/util/Thread.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "util/Thread.h" 24 | 25 | namespace canvas 26 | { 27 | 28 | static void * pthreadRun(void * arg) 29 | { 30 | Thread * thread = static_cast(arg); 31 | thread->run(); 32 | return 0; 33 | } 34 | 35 | Thread::Thread() 36 | : m_running(true) 37 | { 38 | pthread_create(&m_thread, 0, pthreadRun, this); 39 | } 40 | 41 | Thread::~Thread() 42 | { 43 | void * exitStatus; 44 | pthread_join(m_thread, &exitStatus); 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/util/Thread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_THREAD_HEADER 24 | #define CANVAS_THREAD_HEADER 25 | 26 | #include 27 | 28 | namespace canvas 29 | { 30 | class Thread 31 | { 32 | public: 33 | Thread(); 34 | virtual ~Thread(); 35 | 36 | virtual void run() = 0; 37 | 38 | void stop() { m_running = false; } 39 | 40 | protected: 41 | bool m_running; 42 | 43 | private: 44 | pthread_t m_thread; 45 | }; 46 | } 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /tests/tut/tut_macros.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_MACROS_HPP 2 | #define TUT_MACROS_HPP 3 | 4 | #include 5 | 6 | #ifdef ensure_THROW 7 | #error ensure_THROW macro is already defined 8 | #endif 9 | 10 | /** Helper macros to ensure that a call throws exception. 11 | * \code 12 | * #include 13 | * ensure_THROW( this_function_should_throw_bad_alloc(), std::bad_alloc ); 14 | * \endcode 15 | */ 16 | #define ensure_THROW( x, e ) \ 17 | try \ 18 | { \ 19 | x; \ 20 | fail(#x " has not thrown expected exception " #e); \ 21 | } \ 22 | catch(const e &) \ 23 | { \ 24 | } \ 25 | catch(const std::exception &ex) \ 26 | { \ 27 | fail( std::string(#x " has thrown unexpected exception ")+tut::type_name(ex)+": "+ex.what()); \ 28 | } \ 29 | catch(...) \ 30 | { \ 31 | fail(#x " has thrown unexpected unknown exception"); \ 32 | } 33 | 34 | #ifdef ensure_NO_THROW 35 | #error ensure_NO_THROW macro is already defined 36 | #endif 37 | 38 | /** Helper macro to ensure a call does not throw any exceptions. 39 | * \code 40 | * #include 41 | * ensure_NO_THROW( this_function_should_never_throw() ); 42 | * \endcode 43 | */ 44 | #define ensure_NO_THROW( x ) \ 45 | try \ 46 | { \ 47 | x; \ 48 | } \ 49 | catch(const std::exception &ex) \ 50 | { \ 51 | fail( std::string(#x " has thrown unexpected exception ")+tut::type_name(ex)+": "+ex.what()); \ 52 | } \ 53 | catch(...) \ 54 | { \ 55 | fail(#x " has thrown unexpected unknown exception"); \ 56 | } 57 | 58 | #ifdef __COUNTER__ 59 | #define TUT_TESTCASE(object) template<> template<> void object::test<__COUNTER__>() 60 | #endif 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /src/ColorParser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_COLOR_PARSER_HEADER 24 | #define CANVAS_COLOR_PARSER_HEADER 25 | 26 | #include "Color.h" 27 | #include 28 | #include 29 | 30 | namespace canvas 31 | { 32 | 33 | class ColorParser 34 | { 35 | typedef std::map ColorMap; 36 | 37 | public: 38 | ColorParser(); 39 | 40 | Color parse(std::string const& color); 41 | 42 | int hexStringToInt(std::string const& str); 43 | 44 | private: 45 | ColorMap m_cached; 46 | }; 47 | 48 | } 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /src/util/Timer.mm: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifdef PLATFORM_MAC 24 | 25 | #import "Timer.h" 26 | #import 27 | 28 | namespace canvas 29 | { 30 | Timer::Timer() 31 | { 32 | reset(); 33 | } 34 | 35 | void Timer::reset() 36 | { 37 | m_timeStamp = (double)[NSDate timeIntervalSinceReferenceDate]; 38 | } 39 | 40 | double Timer::seconds() 41 | { 42 | double timeStamp = (double)[NSDate timeIntervalSinceReferenceDate]; 43 | return timeStamp - m_timeStamp; 44 | } 45 | } 46 | 47 | #else 48 | # error Should not compile Timer.mm on any other platform than OS X. 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /src/util/Timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_TIMER_HEADER 24 | #define CANVAS_TIMER_HEADER 25 | 26 | #ifdef PLATFORM_LINUX 27 | # include 28 | #endif 29 | 30 | namespace canvas 31 | { 32 | class Timer 33 | { 34 | public: 35 | Timer(); 36 | 37 | // Reset the timer. 38 | void reset(); 39 | 40 | // Returns number of seconds passed since reset was called. 41 | double seconds(); 42 | 43 | private: 44 | #ifdef PLATFORM_LINUX 45 | struct timespec m_timeStamp; 46 | #elif PLATFORM_MAC 47 | double m_timeStamp; 48 | #endif 49 | }; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/State.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "State.h" 24 | 25 | namespace canvas 26 | { 27 | State::State() 28 | : lineWidth(1.0f), 29 | lineCapString("butt"), 30 | strokeStyleString("black"), 31 | fillStyleString("black"), 32 | strokeStyle(Color(0, 0, 0)), 33 | fillStyle(Color(0, 0, 0)), 34 | globalAlpha(1.0f) 35 | { } 36 | 37 | SkPaint::Cap State::skiaCap() const 38 | { 39 | if (lineCapString == "round") 40 | return SkPaint::kRound_Cap; 41 | else if (lineCapString == "square") 42 | return SkPaint::kSquare_Cap; 43 | return SkPaint::kButt_Cap; 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/State.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_STATE_HEADER 24 | #define CANVAS_STATE_HEADER 25 | 26 | #include 27 | #include 28 | 29 | #include "Color.h" 30 | 31 | namespace canvas 32 | { 33 | class State 34 | { 35 | public: 36 | State(); 37 | 38 | float lineWidth; 39 | std::string lineCapString; 40 | 41 | std::string strokeStyleString; 42 | std::string fillStyleString; 43 | Color strokeStyle; 44 | Color fillStyle; 45 | 46 | float globalAlpha; 47 | 48 | SkPaint::Cap skiaCap() const; 49 | }; 50 | } 51 | 52 | #endif 53 | 54 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | PROJECT(CANVAS_CPP CXX) 3 | 4 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1) 5 | 6 | SET(SKIA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/skia/include") 7 | SET(SKIA_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/skia/out") 8 | SET(V8_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/v8/include") 9 | SET(V8_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/v8") 10 | 11 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 12 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 13 | 14 | # Always build with debug symbols for now. 15 | LIST(APPEND CMAKE_CXX_FLAGS -g) 16 | 17 | IF(UNIX) 18 | IF(APPLE) 19 | FIND_LIBRARY(Carbon_FRAMEWORK Carbon) 20 | FIND_LIBRARY(Cocoa_FRAMEWORK Cocoa) 21 | 22 | IF (Carbon_FRAMEWORK-NOTFOUND) 23 | MESSAGE(FATAL_ERROR "Did not find Carbon Framework") 24 | ENDIF (Carbon_FRAMEWORK-NOTFOUND) 25 | 26 | SET(CMAKE_OSX_ARCHITECTURES i386) #;x86_64 27 | ADD_DEFINITIONS("-DPLATFORM_MAC") 28 | ELSE() 29 | FIND_PACKAGE(Freetype) 30 | ADD_DEFINITIONS("-DPLATFORM_LINUX") 31 | ENDIF() 32 | ENDIF(UNIX) 33 | 34 | FIND_PACKAGE(SDL) 35 | FIND_PACKAGE(SDL_image) 36 | FIND_PACKAGE(Boost REQUIRED) 37 | 38 | INCLUDE_DIRECTORIES( 39 | "${CMAKE_CURRENT_SOURCE_DIR}/include" 40 | "${CMAKE_CURRENT_SOURCE_DIR}/src" 41 | "${CMAKE_CURRENT_SOURCE_DIR}/tests" 42 | "${SKIA_INCLUDE_DIR}" 43 | "${SKIA_INCLUDE_DIR}/config" 44 | "${V8_INCLUDE_DIR}" 45 | "${SDL_INCLUDE_DIR}" 46 | "${SDLIMAGE_INCLUDE_DIR}" 47 | "${Boost_INCLUDE_DIR}" 48 | ) 49 | 50 | LINK_DIRECTORIES( 51 | "${SKIA_LIB_DIR}" 52 | "${V8_LIB_DIR}" 53 | ) 54 | 55 | ADD_SUBDIRECTORY(src) 56 | ADD_SUBDIRECTORY(tests) 57 | 58 | # We need SDL and SDL_image to be able to build the demo application 59 | IF (SDL_FOUND OR SDLIMAGE_FOUND) 60 | ADD_SUBDIRECTORY(examples) 61 | ELSE() 62 | MESSAGE("Demo will not be built, because SDL and/or SDL_image could not be found.") 63 | ENDIF() 64 | -------------------------------------------------------------------------------- /src/ImageData.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef IMAGE_DATA_HEADER 24 | #define IMAGE_DATA_HEADER 25 | 26 | #include 27 | #include "Canvas.h" 28 | 29 | namespace canvas 30 | { 31 | 32 | class ImageData 33 | { 34 | public: 35 | ImageData(void * data, int width, int height, Canvas::Format format); 36 | ImageData(ImageData const& other); 37 | 38 | ~ImageData(); 39 | 40 | int width() const; 41 | int height() const; 42 | void setWidth(int); 43 | void setHeight(int); 44 | 45 | SkBitmap const& bitmap() const { return *m_bitmap; } 46 | 47 | private: 48 | SkBitmap * m_bitmap; 49 | Canvas::Format m_format; 50 | }; 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/ImageData.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ImageData.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace canvas 8 | { 9 | 10 | ImageData::ImageData(void * data, int width, int height, Canvas::Format format) 11 | : m_bitmap(new SkBitmap()), 12 | m_format(format) 13 | { 14 | assert(data); 15 | 16 | m_bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); 17 | m_bitmap->allocPixels(); 18 | 19 | m_bitmap->lockPixels(); 20 | 21 | if (format == Canvas::kRGBA) 22 | { 23 | unsigned char * targetData = static_cast(m_bitmap->getPixels()); 24 | unsigned char * sourceData = static_cast(data); 25 | 26 | for (size_t i = 0; i < m_bitmap->getSize(); i += 4) 27 | { 28 | targetData[i + 0] = sourceData[i + 3]; 29 | targetData[i + 1] = sourceData[i + 0]; 30 | targetData[i + 2] = sourceData[i + 1]; 31 | targetData[i + 3] = sourceData[i + 2]; 32 | } 33 | } 34 | else 35 | { 36 | memcpy(m_bitmap->getPixels(), data, m_bitmap->getSize()); 37 | } 38 | 39 | m_bitmap->unlockPixels(); 40 | } 41 | 42 | ImageData::ImageData(ImageData const& other) 43 | : m_bitmap(other.m_bitmap), 44 | m_format(other.m_format) 45 | { 46 | } 47 | 48 | ImageData::~ImageData() 49 | { 50 | delete m_bitmap; 51 | } 52 | 53 | int ImageData::width() const 54 | { 55 | assert(m_bitmap); 56 | return m_bitmap->width(); 57 | } 58 | 59 | int ImageData::height() const 60 | { 61 | assert(m_bitmap); 62 | return m_bitmap->height(); 63 | } 64 | 65 | void ImageData::setWidth(int) 66 | { 67 | assert(0 && "Invalid operation, not allowed to set width!"); 68 | } 69 | 70 | void ImageData::setHeight(int) 71 | { 72 | assert(0 && "Invalid operation, not allowed to set height!"); 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /src/Script.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_SCRIPT_HEADER 24 | #define CANVAS_SCRIPT_HEADER 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace canvas 31 | { 32 | class Script 33 | { 34 | public: 35 | 36 | Script(v8::Handle context); 37 | ~Script(); 38 | 39 | bool load(std::string const& filename); 40 | bool load(std::vector const& files); 41 | 42 | bool runString(std::string const& string, std::string const& filename = ""); 43 | 44 | /// Returns a global script object that match the supplied name. 45 | v8::Local getObject(std::string const& name); 46 | 47 | v8::Handle context() const { return m_context; } 48 | 49 | private: 50 | 51 | v8::Persistent m_context; 52 | }; 53 | } 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /src/util/Timer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Timer.h" 24 | 25 | #ifdef PLATFORM_LINUX 26 | #include 27 | #endif 28 | 29 | namespace canvas 30 | { 31 | Timer::Timer() 32 | { 33 | reset(); 34 | } 35 | 36 | void Timer::reset() 37 | { 38 | #ifdef PLATFORM_LINUX 39 | if (clock_gettime(CLOCK_REALTIME, &m_timeStamp) == -1) 40 | { 41 | perror("clock_gettime"); 42 | m_timeStamp.tv_sec = 0; 43 | m_timeStamp.tv_nsec = 0; 44 | } 45 | #else 46 | # warning Timer::reset() not implemented on this platform. 47 | #endif 48 | } 49 | 50 | double Timer::seconds() 51 | { 52 | #ifdef PLATFORM_LINUX 53 | struct timespec timeStamp; 54 | 55 | if (clock_gettime(CLOCK_REALTIME, &timeStamp) == -1) 56 | { 57 | perror("clock_gettime"); 58 | return -1.0; 59 | } 60 | 61 | return (timeStamp.tv_sec - m_timeStamp.tv_sec) + 1e-9 * (timeStamp.tv_nsec - m_timeStamp.tv_nsec); 62 | #else 63 | # warning Timer::seconds() not implemented on this platform. 64 | #endif 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/Callback.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_CALLBACK_HEADER 24 | #define CANVAS_CALLBACK_HEADER 25 | 26 | #include 27 | 28 | namespace canvas 29 | { 30 | class Callback 31 | { 32 | public: 33 | 34 | Callback(v8::Handle func, int interval) 35 | : m_interval(static_cast(interval) / 1000.0), 36 | m_current(0.0) 37 | { 38 | m_function = v8::Persistent::New(func); 39 | } 40 | 41 | v8::Handle call(double dt) 42 | { 43 | m_current += dt; 44 | 45 | if (m_current > m_interval) 46 | { 47 | m_current -= m_interval; 48 | return m_function->Call(m_function, 0, NULL); 49 | } 50 | 51 | return v8::Undefined(); 52 | } 53 | 54 | private: 55 | 56 | v8::Persistent m_function; 57 | double m_interval; 58 | double m_current; 59 | }; 60 | } 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /tests/ColorParserTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "../src/ColorParser.h" 4 | 5 | using namespace canvas; 6 | 7 | namespace tut 8 | { 9 | struct ColorParserData 10 | { 11 | ColorParser parser; 12 | }; 13 | 14 | test_group tf("ColorParser"); 15 | typedef test_group::object object; 16 | 17 | template <> 18 | template <> 19 | void object::test<1>() 20 | { 21 | set_test_name("Check Hex string -> Int"); 22 | 23 | ensure(parser.hexStringToInt("0") == 0); 24 | ensure(parser.hexStringToInt("1") == 1); 25 | ensure(parser.hexStringToInt("2") == 2); 26 | ensure(parser.hexStringToInt("3") == 3); 27 | ensure(parser.hexStringToInt("4") == 4); 28 | ensure(parser.hexStringToInt("5") == 5); 29 | ensure(parser.hexStringToInt("6") == 6); 30 | ensure(parser.hexStringToInt("7") == 7); 31 | ensure(parser.hexStringToInt("8") == 8); 32 | ensure(parser.hexStringToInt("9") == 9); 33 | ensure(parser.hexStringToInt("a") == 10); 34 | ensure(parser.hexStringToInt("b") == 11); 35 | ensure(parser.hexStringToInt("c") == 12); 36 | ensure(parser.hexStringToInt("d") == 13); 37 | ensure(parser.hexStringToInt("e") == 14); 38 | ensure(parser.hexStringToInt("f") == 15); 39 | ensure(parser.hexStringToInt("A") == 10); 40 | ensure(parser.hexStringToInt("B") == 11); 41 | ensure(parser.hexStringToInt("C") == 12); 42 | ensure(parser.hexStringToInt("D") == 13); 43 | ensure(parser.hexStringToInt("E") == 14); 44 | ensure(parser.hexStringToInt("F") == 15); 45 | } 46 | 47 | template<> 48 | template<> 49 | void object::test<2>() 50 | { 51 | set_test_name("Check Color equal operator"); 52 | ensure(Color(1.0f, 1.0f, 0.0f, 0.4f) == Color(1.0f, 1.0f, 0.0f, 0.4f)); 53 | } 54 | 55 | template <> 56 | template <> 57 | void object::test<3>() 58 | { 59 | set_test_name("Check built-in colors"); 60 | ensure(parser.parse("red") == Color(255, 0, 0)); 61 | ensure(parser.parse("blue") == Color(0, 0, 255)); 62 | ensure(parser.parse("green") == Color(0, 255, 0)); 63 | ensure(parser.parse("yellow") == Color(255,255,0)); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/binding/Object.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Object.h" 24 | 25 | namespace binding { 26 | 27 | v8::Handle scriptCallback(v8::Arguments const& args) 28 | { 29 | v8::HandleScope scope; 30 | BaseFunctor * func = static_cast(v8::External::Unwrap(args.Data())); 31 | return scope.Close(func->call(args)); 32 | } 33 | 34 | v8::Handle scriptConstructor(v8::Arguments const& args) 35 | { 36 | return v8::Undefined(); 37 | } 38 | 39 | void attributeSetCallback(v8::Local name, v8::Local value, v8::AccessorInfo const& info) 40 | { 41 | v8::HandleScope scope; 42 | BaseAttribute * attrib = static_cast(v8::External::Unwrap(info.Data())); 43 | attrib->set(value, info); 44 | } 45 | 46 | v8::Handle attributeGetCallback(v8::Local name, v8::AccessorInfo const& info) 47 | { 48 | v8::HandleScope scope; 49 | BaseAttribute * attrib = static_cast(v8::External::Unwrap(info.Data())); 50 | return scope.Close(attrib->get(info)); 51 | } 52 | 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/Color.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_COLOR_HEADER 24 | #define CANVAS_COLOR_HEADER 25 | 26 | #include 27 | #include 28 | 29 | namespace canvas 30 | { 31 | 32 | class Color 33 | { 34 | public: 35 | Color() 36 | : r(0.0f), 37 | g(0.0f), 38 | b(0.0f), 39 | a(1.0f) 40 | { } 41 | 42 | Color(float r, float g, float b, float a = 1.0f) 43 | : r(r), 44 | g(g), 45 | b(b), 46 | a(a) 47 | { } 48 | 49 | Color(int r, int g, int b, int a = 255) 50 | : r(r / 255.0f), 51 | g(g / 255.0f), 52 | b(b / 255.0f), 53 | a(a / 255.0f) 54 | { } 55 | 56 | Color(Color const& c) 57 | : r(c.r), 58 | g(c.g), 59 | b(c.b), 60 | a(c.a) 61 | { } 62 | 63 | bool operator == (Color const& other) 64 | { 65 | return std::abs(r - other.r) < 1e-5f && 66 | std::abs(g - other.g) < 1e-5f && 67 | std::abs(b - other.b) < 1e-5f && 68 | std::abs(a - other.a) < 1e-5f; 69 | } 70 | 71 | SkColor toSkia() const 72 | { 73 | SkColorSetARGB((int)(a * 255), 74 | (int)(r * 255), 75 | (int)(g * 255), 76 | (int)(b * 255)); 77 | } 78 | 79 | float r, g, b, a; 80 | }; 81 | 82 | } 83 | 84 | #endif 85 | 86 | -------------------------------------------------------------------------------- /include/Canvas.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_HEADER 24 | #define CANVAS_HEADER 25 | 26 | #include 27 | #include 28 | 29 | namespace canvas 30 | { 31 | // Forward declaration 32 | class CanvasData; 33 | 34 | class Canvas 35 | { 36 | private: 37 | Canvas(Canvas const& other); 38 | Canvas & operator = (Canvas const& other); 39 | 40 | public: 41 | enum Format 42 | { 43 | kARGB, //!< Default format, 32-bits per pixel in (alpha, red, blue, green) configuration. 44 | kRGBA //!< If this format is used, an internal byte swap will be performed on every paint() call. 45 | }; 46 | 47 | Canvas(int width, int height, Format format = kARGB, bool threaded = true); 48 | ~Canvas(); 49 | 50 | /// Loads a script from file and executes it. 51 | void startWithFile(std::string const& filename); 52 | 53 | /// Loads and executes the supplied javascript code. 54 | void startWithCode(std::string const& code); 55 | 56 | /// Register image data with the canvas, it can later be accessed from javascript. 57 | void registerImage(std::string const& name, int width, int height, Format format, void * data); 58 | 59 | /// Returns true if the canvas should be rendered. 60 | bool isDirty() const; 61 | 62 | /// Paint the canvas to the supplied image data. 63 | /// Note that the image format is 32-bits per pixel 64 | /// organized in ARGB. 65 | void paint(void * imageData); 66 | 67 | /// Pops and returns the last javascript log entry. 68 | /// Returns the empty string if no log entires exists. 69 | std::string lastLogEntry(); 70 | 71 | private: 72 | std::auto_ptr m_data; 73 | }; 74 | } 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /tests/tut/tut_main.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_MAIN_H 2 | #define TUT_MAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tut 11 | { 12 | 13 | /** Helper function to make test binaries simpler. 14 | * 15 | * Example of basic usage follows. 16 | * 17 | * @code 18 | * namespace tut { test_runner_singleton runner; } 19 | * 20 | * int main(int argc, char **argv) 21 | * { 22 | * if( tut_main(argc, argv) ) 23 | * return 0; 24 | * else 25 | * return -1; 26 | * } 27 | * @endcode 28 | * 29 | * It is also possible to do some generic initialization before 30 | * running any tests and cleanup before exiting application. 31 | * Note that tut_main can throw tut::no_such_group or tut::no_such_test. 32 | * 33 | * @code 34 | * namespace tut { test_runner_singleton runner; } 35 | * 36 | * int main(int argc, char **argv) 37 | * { 38 | * tut::xml_reporter reporter; 39 | * tut::runner.get().insert_callback(&reporter); 40 | * 41 | * MyInit(); 42 | * try 43 | * { 44 | * tut_main(argc, argv); 45 | * } 46 | * catch(const tut::tut_error &ex) 47 | * { 48 | * std::cerr << "TUT error: " << ex.what() << std::endl; 49 | * } 50 | * MyCleanup(); 51 | * } 52 | * @endcode 53 | */ 54 | inline bool tut_main(int argc, const char * const * const argv, std::ostream &os = std::cerr) 55 | { 56 | std::stringstream usage; 57 | usage << "Usage: " << argv[0] << " [group] [testcase]" << std::endl; 58 | groupnames gr = runner.get().list_groups(); 59 | usage << "Available test groups:" << std::endl; 60 | for(groupnames::const_iterator i = gr.begin(); i != gr.end(); ++i) 61 | { 62 | usage << " " << *i << std::endl; 63 | } 64 | 65 | if(argc>1) 66 | { 67 | if(std::string(argv[1]) == "-h" || 68 | std::string(argv[1]) == "--help" || 69 | std::string(argv[1]) == "/?" || 70 | argc > 3) 71 | { 72 | os << usage.rdbuf(); 73 | return false; 74 | } 75 | } 76 | 77 | // Check command line options. 78 | switch(argc) 79 | { 80 | case 1: 81 | runner.get().run_tests(); 82 | break; 83 | 84 | case 2: 85 | runner.get().run_tests(argv[1]); 86 | break; 87 | 88 | case 3: 89 | { 90 | char *end; 91 | int t = strtol(argv[2], &end, 10); 92 | if(end != argv[2] + strlen(argv[2])) 93 | { 94 | throw no_such_test("`" + std::string(argv[2]) + "` should be a number"); 95 | } 96 | 97 | test_result tr; 98 | if(!runner.get().run_test(argv[1], t, tr) || tr.result == test_result::dummy) 99 | { 100 | throw no_such_test("No testcase `" + std::string(argv[2]) + "` in group `" + argv[1] + "`"); 101 | } 102 | } 103 | break; 104 | } 105 | 106 | return true; 107 | } // tut_main() 108 | 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /tests/CanvasTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "Canvas.h" 4 | 5 | using namespace canvas; 6 | 7 | namespace tut 8 | { 9 | struct CanvasData 10 | { 11 | CanvasData() 12 | : canvas(new Canvas(100, 100, Canvas::kARGB, false)) 13 | { } 14 | 15 | ~CanvasData() 16 | { 17 | delete canvas; 18 | } 19 | 20 | Canvas * canvas; 21 | }; 22 | 23 | test_group canvasTest("Canvas"); 24 | typedef test_group::object object; 25 | 26 | template <> 27 | template <> 28 | void object::test<1>() 29 | { 30 | set_test_name("Canvas allocation"); 31 | } 32 | 33 | template <> 34 | template <> 35 | void object::test<2>() 36 | { 37 | set_test_name("Javascript Test 1"); 38 | 39 | canvas->startWithCode(""); 40 | } 41 | 42 | template <> 43 | template <> 44 | void object::test<3>() 45 | { 46 | set_test_name("Javascript Test 2: console.log()"); 47 | 48 | canvas->startWithCode("console.log(\"Hello, World!\")"); 49 | ensure(canvas->lastLogEntry() == "Hello, World!"); 50 | } 51 | 52 | template <> 53 | template <> 54 | void object::test<4>() 55 | { 56 | set_test_name("Javascript Test 3: window.setInterval()"); 57 | 58 | canvas->startWithCode("window.setInterval(function() { console.log(\"Hello, World!\"); });"); 59 | ensure(canvas->lastLogEntry() == ""); 60 | 61 | canvas->paint(0); 62 | canvas->paint(0); 63 | 64 | // After we have painter two times, we should have two "Hello, World!" messages in the history 65 | ensure(canvas->lastLogEntry() == "Hello, World!"); 66 | ensure(canvas->lastLogEntry() == "Hello, World!"); 67 | ensure(canvas->lastLogEntry() == ""); 68 | } 69 | 70 | template <> 71 | template <> 72 | void object::test<5>() 73 | { 74 | set_test_name("Javascript Test 4: window.getContext('')"); 75 | 76 | canvas->startWithCode("console.log(window.getContext('') == undefined ? 'True' : 'False')"); 77 | ensure(canvas->lastLogEntry() == "True"); 78 | } 79 | 80 | template <> 81 | template <> 82 | void object::test<6>() 83 | { 84 | set_test_name("Javascript Test 5: window.getContext('2d')"); 85 | 86 | canvas->startWithCode("console.log(window.getContext('2d') != undefined ? 'True' : 'False')"); 87 | ensure(canvas->lastLogEntry() == "True"); 88 | } 89 | 90 | template <> 91 | template <> 92 | void object::test<7>() 93 | { 94 | set_test_name("Javascript Test 6: Test attribute lineWidth"); 95 | 96 | canvas->startWithCode("var ctx = window.getContext('2d'); ctx.lineWidth = 2.0; console.log(ctx.lineWidth);"); 97 | ensure(canvas->lastLogEntry() == "2"); 98 | } 99 | 100 | template <> 101 | template <> 102 | void object::test<8>() 103 | { 104 | set_test_name("Javascript Test 7: Test attribute lineCap"); 105 | 106 | canvas->startWithCode("var ctx = window.getContext('2d'); ctx.lineCap = 'round'; console.log(ctx.lineCap);"); 107 | ensure(canvas->lastLogEntry() == "round"); 108 | } 109 | 110 | template <> 111 | template <> 112 | void object::test<9>() 113 | { 114 | set_test_name("Javascript Test 8: width/height attributes"); 115 | 116 | canvas->startWithCode("console.log(window.width); console.log(window.height);"); 117 | ensure(canvas->lastLogEntry() == "100"); 118 | ensure(canvas->lastLogEntry() == "100"); 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/binding/Attribute.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef V8_SCRIPT_ATTRIBUTE_HPP 24 | #define V8_SCRIPT_ATTRIBUTE_HPP 25 | 26 | #include "v8.h" 27 | #include "Translate.h" 28 | #include "FunctionInfo.h" 29 | 30 | namespace binding { 31 | 32 | class BaseAttribute 33 | { 34 | public: 35 | virtual v8::Handle get(v8::AccessorInfo const& info) 36 | { 37 | return v8::Undefined(); 38 | } 39 | 40 | virtual void set(v8::Handle const& value, v8::AccessorInfo const& info) 41 | { 42 | } 43 | }; 44 | 45 | template 46 | class AttributePtr : public BaseAttribute 47 | { 48 | typedef AttribT ObjectT::*Ptr; 49 | 50 | public: 51 | AttributePtr(Ptr ptr) 52 | : m_ptr(ptr) 53 | { } 54 | 55 | virtual v8::Handle get(v8::AccessorInfo const& info) 56 | { 57 | ObjectT * object = Object::unwrap(info.Holder()); 58 | return Translate::from(object->*m_ptr); 59 | } 60 | 61 | virtual void set(v8::Handle const& value, v8::AccessorInfo const& info) 62 | { 63 | ObjectT * object = Object::unwrap(info.Holder()); 64 | (object->*m_ptr) = Translate::to(value); 65 | } 66 | 67 | private: 68 | Ptr m_ptr; 69 | }; 70 | 71 | template 72 | class AttributeCallback : public BaseAttribute 73 | { 74 | typedef typename FunctionInfo::Return ReturnType; 75 | typedef typename TL::TypeAtNonStrict::Params, EmptyType, 0>::Result SetType; 76 | 77 | public: 78 | AttributeCallback(GetT getMethod, SetT setMethod) 79 | : m_getMethod(getMethod), 80 | m_setMethod(setMethod) 81 | { } 82 | 83 | virtual v8::Handle get(v8::AccessorInfo const& info) 84 | { 85 | ObjectT * object = Object::unwrap(info.Holder()); 86 | 87 | return Translate::from(((*object).*m_getMethod)()); 88 | } 89 | 90 | virtual void set(v8::Handle const& value, v8::AccessorInfo const& info) 91 | { 92 | ObjectT * object = Object::unwrap(info.Holder()); 93 | ((*object).*m_setMethod)(Translate::to(value)); 94 | } 95 | 96 | private: 97 | GetT m_getMethod; 98 | SetT m_setMethod; 99 | }; 100 | 101 | } 102 | 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /src/Painter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_PAINTER_HEADER 24 | #define CANVAS_PAINTER_HEADER 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "Script.h" 31 | #include "Context.h" 32 | #include "Callback.h" 33 | #include "Canvas.h" 34 | #include "ImageData.h" 35 | #include "util/Mutex.h" 36 | #include "util/Timer.h" 37 | #include "binding/Object.h" 38 | 39 | namespace canvas 40 | { 41 | class Painter 42 | { 43 | typedef std::map CallbackMap; 44 | 45 | public: 46 | Painter(int width, int height, Canvas::Format format); 47 | ~Painter(); 48 | 49 | void start(std::string const& fileOrCode, bool isFile = true); 50 | 51 | void draw(); 52 | 53 | void copyImageTo(void * target); 54 | 55 | int setInterval(v8::Handle const& function, int interval); 56 | void clearInterval(int index); 57 | 58 | v8::Handle getContext(std::string const& type); 59 | 60 | void registerImage(std::string const& name, ImageData * image); 61 | v8::Handle getImage(std::string const& name); 62 | 63 | int width() const { return m_width; } 64 | /// Only here because binding system must have a get/set pair. 65 | void setWidth(int); 66 | 67 | int height() const { return m_height; } 68 | /// Only here because binding system must have a get/set pair. 69 | void setHeight(int); 70 | 71 | /// Store a string in the log history. 72 | void log(std::string const& log); 73 | 74 | /// Returns the oldest entry in the history, 75 | /// while also poping it from the list. 76 | std::string lastLogEntry(); 77 | 78 | private: 79 | Mutex m_painterMutex; 80 | Mutex m_imageMutex; 81 | Mutex m_logMutex; 82 | 83 | Timer m_timer; 84 | 85 | int m_width; 86 | int m_height; 87 | Canvas::Format m_format; 88 | 89 | Script * m_script; 90 | Context * m_context; 91 | 92 | std::map m_images; 93 | 94 | /// Stores the log history 95 | std::list m_history; 96 | 97 | CallbackMap m_callbacks; 98 | int m_callbackIndex; 99 | 100 | binding::Object * m_windowBinding; 101 | binding::Object * m_consoleBinding; 102 | binding::Object * m_contextBinding; 103 | binding::Object * m_imageDataBinding; 104 | 105 | v8::Persistent m_scriptTemplate; 106 | }; 107 | } 108 | 109 | #endif 110 | 111 | -------------------------------------------------------------------------------- /tests/tut/tut_result.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_RESULT_H_GUARD 2 | #define TUT_RESULT_H_GUARD 3 | #include 4 | 5 | #include 6 | 7 | #if defined(TUT_USE_RTTI) 8 | #if (defined(_MSC_VER) && !defined(_CPPRTTI)) || (defined(__GNUC__) && !defined(__GXX_RTTI)) 9 | #undef TUT_USE_RTTI 10 | #endif 11 | #endif 12 | 13 | #if defined(TUT_USE_RTTI) 14 | #include 15 | #endif 16 | 17 | namespace tut 18 | { 19 | 20 | #if defined(TUT_USE_RTTI) 21 | template 22 | inline std::string type_name(const T& t) 23 | { 24 | return typeid(t).name(); 25 | } 26 | #else 27 | template 28 | inline std::string type_name(const T& t) 29 | { 30 | return "Unknown type, RTTI disabled"; 31 | } 32 | 33 | inline std::string type_name(const std::exception&) 34 | { 35 | return "Unknown std::exception, RTTI disabled"; 36 | } 37 | #endif 38 | 39 | 40 | #if defined(TUT_USE_POSIX) 41 | struct test_result_posix 42 | { 43 | test_result_posix() 44 | : pid(getpid()) 45 | { 46 | } 47 | 48 | virtual ~test_result_posix() 49 | { 50 | } 51 | 52 | pid_t pid; 53 | }; 54 | #else 55 | struct test_result_posix 56 | { 57 | virtual ~test_result_posix() 58 | { 59 | } 60 | }; 61 | #endif 62 | 63 | /** 64 | * Return type of runned test/test group. 65 | * 66 | * For test: contains result of test and, possible, message 67 | * for failure or exception. 68 | */ 69 | struct test_result : public test_result_posix 70 | { 71 | /** 72 | * Test group name. 73 | */ 74 | std::string group; 75 | 76 | /** 77 | * Test number in group. 78 | */ 79 | int test; 80 | 81 | /** 82 | * Test name (optional) 83 | */ 84 | std::string name; 85 | 86 | /** 87 | * result of a test 88 | */ 89 | enum result_type 90 | { 91 | ok, ///< test finished successfully 92 | fail, ///< test failed with ensure() or fail() methods 93 | ex, ///< test throwed an exceptions 94 | warn, ///< test finished successfully, but test destructor throwed 95 | term, ///< test forced test application to terminate abnormally 96 | ex_ctor, ///< 97 | rethrown, ///< 98 | skipped, ///< 99 | dummy ///< 100 | }; 101 | 102 | result_type result; 103 | 104 | /** 105 | * Exception message for failed test. 106 | */ 107 | std::string message; 108 | std::string exception_typeid; 109 | 110 | /** 111 | * Default constructor. 112 | */ 113 | test_result() 114 | : group(), 115 | test(0), 116 | name(), 117 | result(ok), 118 | message(), 119 | exception_typeid() 120 | { 121 | } 122 | 123 | /** 124 | * Constructor. 125 | */ 126 | test_result(const std::string& grp, int pos, 127 | const std::string& test_name, result_type res) 128 | : group(grp), 129 | test(pos), 130 | name(test_name), 131 | result(res), 132 | message(), 133 | exception_typeid() 134 | { 135 | } 136 | 137 | /** 138 | * Constructor with exception. 139 | */ 140 | test_result(const std::string& grp,int pos, 141 | const std::string& test_name, result_type res, 142 | const std::exception& ex) 143 | : group(grp), 144 | test(pos), 145 | name(test_name), 146 | result(res), 147 | message(ex.what()), 148 | exception_typeid(type_name(ex)) 149 | { 150 | } 151 | 152 | /** Constructor with typeid. 153 | */ 154 | test_result(const std::string& grp,int pos, 155 | const std::string& test_name, result_type res, 156 | const std::string& ex_typeid, 157 | const std::string& msg) 158 | : group(grp), 159 | test(pos), 160 | name(test_name), 161 | result(res), 162 | message(msg), 163 | exception_typeid(ex_typeid) 164 | { 165 | } 166 | 167 | virtual ~test_result() 168 | { 169 | } 170 | }; 171 | 172 | } 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /src/binding/TypeList.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef V8_SCRIPT_TYPE_LIST_HPP 24 | #define V8_SCRIPT_TYPE_LIST_HPP 25 | 26 | #include "Types.h" 27 | 28 | /** 29 | * Convinient macros for defining typelists. 30 | */ 31 | #define TYPELIST_1(T1) \ 32 | TypeList 33 | #define TYPELIST_2(T1, T2) \ 34 | TypeList 35 | #define TYPELIST_3(T1, T2, T3) \ 36 | TypeList 37 | #define TYPELIST_4(T1, T2, T3, T4) \ 38 | TypeList 39 | #define TYPELIST_5(T1, T2, T3, T4, T5) \ 40 | TypeList 41 | #define TYPELIST_6(T1, T2, T3, T4, T5, T6) \ 42 | TypeList 43 | #define TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) \ 44 | TypeList 45 | #define TYPELIST_8(T1, T2, T3, T4, T5, T6, T7, T8) \ 46 | TypeList 47 | #define TYPELIST_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) \ 48 | TypeList 49 | #define TYPELIST_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) \ 50 | TypeList 51 | 52 | /** 53 | * Servs as a collection of types, implemented as a list. 54 | */ 55 | template 56 | struct TypeList 57 | { 58 | typedef T Head; 59 | typedef U Tail; 60 | }; 61 | 62 | namespace TL { 63 | 64 | /** 65 | * Calculates the lenth of a typelist. 66 | */ 67 | template struct Length; 68 | 69 | template <> struct Length 70 | { 71 | enum { Value = 0 }; 72 | }; 73 | 74 | template 75 | struct Length< TypeList > 76 | { 77 | enum { Value = 1 + Length::Value }; 78 | }; 79 | 80 | /** 81 | * Access a type by index in a typelist. 82 | */ 83 | template struct TypeAt; 84 | 85 | template 86 | struct TypeAt, 0> 87 | { 88 | typedef Head Result; 89 | }; 90 | 91 | template 92 | struct TypeAt, i> 93 | { 94 | typedef typename TypeAt::Result Result; 95 | }; 96 | 97 | /** 98 | * Access a type by index. If index is outside of list, 99 | * a default value is returned. 100 | */ 101 | template struct TypeAtNonStrict; 102 | 103 | template 104 | struct TypeAtNonStrict, Default, 0> 105 | { 106 | typedef Head Result; 107 | }; 108 | 109 | template 110 | struct TypeAtNonStrict 111 | { 112 | typedef Default Result; 113 | }; 114 | 115 | template 116 | struct TypeAtNonStrict, Default, index> 117 | { 118 | typedef typename TypeAtNonStrict::Result Result; 119 | }; 120 | 121 | 122 | } 123 | 124 | #endif 125 | 126 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Canvas++ 2 | 3 | An implementation of the JavaScript canvas api, written in C++. 4 | 5 | Modern browsers that support HTML5 comes with a handy element called the canvas. It provides a surface that can be drawn upon using JavaScript. Using this canvas all sorts of things can be created. 6 | 7 | This library makes it possible to embed such a canvas into another application. This is especially useful for games that can use the canvas to draw it's UI's. 8 | 9 | h2. Building 10 | 11 | OS X is the only supported platform at the moment, and you need to have both cmake and boost installed to be able to build the project. 12 | 13 | To build the dependencies Skia and V8 execute the following command: 14 | @./deps/fetch_and_build.sh@ 15 | 16 | Create a build folder, this step is optional, but it's encouraged. It makes cleaning up a lot easier, especially because cmake creates a lot of files all over the place: 17 | @mkdir build@ 18 | @cd build@ 19 | 20 | Generate makefiles for the project: 21 | @cmake -DCMAKE_BUILD_TYPE=Debug ..@ 22 | 23 | Compile: 24 | @make@ 25 | 26 | When this is done, the demo application can be located and started from the @build/bin@ directory. 27 | @./build/bin/demo@ 28 | 29 | h2. Example 30 | 31 | A simple example that creates a threaded canvas and load a JavaScript file. 32 | 33 | bc. Canvas * canvas = new Canvas(800, 600, Canvas::kARGB, true); 34 | canvas->startWithFile("..."); 35 | //canvas->startWithCode("..."); We can just as well supply a string containing code. 36 | 37 | It is only possible to call either @startWithFile("...")@ or @startWithCode("...")@ once. The second call to one of the functions will throw an assert. 38 | 39 | We need to have some target that our canvas should paint to. This could for example be a @SDL_Surface@. 40 | 41 | bc. void * imageTarget = ...; 42 | 43 | Then we ask the canvas to paint into our target. 44 | 45 | bc. if (canvas->isDirty()) 46 | canvas->paint(imageTarget); 47 | 48 | 49 | h2. JavaScript API 50 | 51 | There are some differences between the HTML5 canvas api and Canvas++. Most notably is the @getContext()@ function. Instead of calling it on the canvas dom element, it's located on the window object. So we need to call @window.getContext('2d')@. 52 | 53 | The same apply to the @width@ and @height@ attributes. Instead of being located on the dom element, they are accessed through the window object, @window.width@ and @window.height@. 54 | 55 | h3. Window Object 56 | 57 | Accessed through the global @window@ object. 58 | 59 | * @Object getContext(string type)@ - Returns the graphics context. The only valid context is '2d'. 60 | * @int setInterval(function func)@ - Register a function that will be called when the canvas should repaint itself. Returns an integer identifying the callback function. 61 | * @clearInterval(int id)@ - Removes the callback function with the corresponding id. 62 | * @int width@ - The width of the window. 63 | * @int height@ - The height of the window. 64 | 65 | h3. Console Object 66 | 67 | Accessed through the global @console@ object. 68 | 69 | * @void log(string text)@ - Output a string to the log system. 70 | 71 | h3. Context object 72 | 73 | List of all the methods and attributes that are currently implemented. 74 | 75 | * @string fillStyle@ 76 | * @string strokeStyle@ 77 | * @float lineWidth@ 78 | * @string lineCap@ 79 | * @float globalAlpha@ 80 | * @void scale(float x, float y)@ 81 | * @void rotate(float angle)@ 82 | * @void translate(float x, float y)@ 83 | * @void drawImage(Object image, float x, float y, [Optional] float width, float height)@ 84 | * @void beginPath()@ 85 | * @void closePath()@ 86 | * @void fill()@ 87 | * @void stroke()@ 88 | * @void moveTo(float x, float y)@ 89 | * @void lineTo(float x, float y)@ 90 | * @void quadraticCurveTo(float cpx, float cpy, float x, float y)@ 91 | * @void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)@ 92 | * @void arcTo(float x1, float y1, float x2, float y2, float radius)@ 93 | * @void rect(float x, float y, float width, float height)@ 94 | * @void fillRect(float x, float y, float width, float height)@ 95 | * @void strokeRect(float x, float y, float width, float height)@ 96 | * @void clearRect(float x, float y, float width, float height)@ 97 | * @void clear() - Non standard function that clears the whole canvas.@ 98 | 99 | h2. License 100 | 101 | See the LICENSE file for legal information. 102 | -------------------------------------------------------------------------------- /src/Context.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CANVAS_CONTEXT_HEADER 24 | #define CANVAS_CONTEXT_HEADER 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include "State.h" 38 | #include "Canvas.h" 39 | #include "ColorParser.h" 40 | #include "ImageData.h" 41 | 42 | namespace canvas 43 | { 44 | class ContextData; 45 | 46 | class Context 47 | { 48 | public: 49 | Context(int width, int height, Canvas::Format format); 50 | ~Context(); 51 | 52 | void copyImageTo(void * target); 53 | 54 | // Styles 55 | float lineWidth() const; 56 | void setLineWidth(float width); 57 | 58 | std::string lineCap() const; 59 | void setLineCap(std::string const& cap); 60 | 61 | std::string strokeStyle() const; 62 | void setStrokeStyle(std::string const& style); 63 | std::string fillStyle() const; 64 | void setFillStyle(std::string const& style); 65 | 66 | float globalAlpha() const; 67 | void setGlobalAlpha(float alpha); 68 | 69 | // Transformations 70 | void scale(float x, float y); 71 | void rotate(float angle); 72 | void translate(float x, float y); 73 | 74 | // Image function 75 | void drawImage(ImageData * image, float x, float y, float width, float height); 76 | static v8::Handle drawImageCallback(v8::Arguments const& args); 77 | 78 | // Path functions 79 | void beginPath(); 80 | void closePath(); 81 | 82 | void fill(); 83 | void stroke(); 84 | void clip(); 85 | 86 | void moveTo(float x, float y); 87 | void lineTo(float x, float y); 88 | 89 | void quadraticCurveTo(float cpx, float cpy, float x, float y); 90 | void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y); 91 | 92 | void arcTo(float x1, float y1, float x2, float y2, float radius); 93 | 94 | void rect(float x, float y, float width, float height); 95 | 96 | void fillRect(float x, float y, float width, float height); 97 | void strokeRect(float x, float y, float width, float height); 98 | 99 | void clear(); 100 | void clearRect(float x, float y, float width, float height); 101 | 102 | private: 103 | inline State & currentState() { return m_stateStack.back(); } 104 | inline State const& currentState() const { return m_stateStack.back(); } 105 | 106 | void syncPaintWithState(); 107 | 108 | private: 109 | SkBitmap * m_bitmap; 110 | SkDevice * m_device; 111 | SkCanvas * m_canvas; 112 | SkPath m_path; 113 | 114 | SkPaint m_fillPaint; 115 | SkPaint m_strokePaint; 116 | 117 | ColorParser m_parser; 118 | 119 | int m_width; 120 | int m_height; 121 | Canvas::Format m_format; 122 | 123 | std::list m_stateStack; 124 | }; 125 | 126 | } 127 | 128 | #endif 129 | 130 | -------------------------------------------------------------------------------- /src/Script.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Script.h" 24 | #include 25 | #include 26 | 27 | namespace canvas 28 | { 29 | Script::Script(v8::Handle context) 30 | { 31 | m_context = v8::Persistent::New(context); 32 | } 33 | 34 | Script::~Script() 35 | { 36 | } 37 | 38 | v8::Local Script::getObject(std::string const& name) 39 | { 40 | v8::HandleScope scope; 41 | v8::Context::Scope contextScope(m_context); 42 | 43 | return scope.Close(m_context->Global()->Get(v8::String::New(name.c_str()))); 44 | } 45 | 46 | bool Script::load(std::string const& filename) 47 | { 48 | std::vector data; 49 | 50 | // Read file 51 | std::ifstream inf(filename.c_str(), std::ios::binary); 52 | if (!inf.good()) 53 | { 54 | inf.close(); 55 | return false; 56 | } 57 | 58 | char ch; 59 | while (inf.get(ch)) 60 | data.push_back(ch); 61 | 62 | inf.close(); 63 | 64 | data.push_back('\0'); 65 | 66 | return runString(std::string(&data[0]), filename); 67 | } 68 | 69 | bool Script::load(std::vector const& files) 70 | { 71 | std::vector data; 72 | 73 | // Load all the files 74 | for (std::vector::const_iterator it = files.begin(); it != files.end(); ++it) 75 | { 76 | std::string filename = *it; 77 | 78 | // Read file 79 | std::ifstream inf(filename.c_str(), std::ios::binary); 80 | if (inf.good()) 81 | { 82 | // Read file 83 | char ch; 84 | while (inf.get(ch)) 85 | data.push_back(ch); 86 | } 87 | else 88 | std::cerr << "Could not read file '" << filename << "'" << std::endl; 89 | 90 | // Insert a newline between each file 91 | data.push_back('\n'); 92 | inf.close(); 93 | } 94 | 95 | data.push_back('\0'); 96 | return runString(std::string(&data[0]), ""); 97 | } 98 | 99 | 100 | bool Script::runString(std::string const& code, std::string const& filename) 101 | { 102 | v8::HandleScope scope; 103 | v8::Context::Scope contextScope(m_context); 104 | v8::TryCatch tryCatch; 105 | 106 | // Create a v8 string to hold the source 107 | v8::Handle source = v8::String::New(code.c_str(), code.size()); 108 | 109 | // Compile the script 110 | v8::Handle script = v8::Script::Compile(source, v8::String::New(filename.c_str())); 111 | if (script.IsEmpty()) 112 | { 113 | v8::String::Utf8Value error(tryCatch.Exception()); 114 | v8::Handle message = tryCatch.Message(); 115 | 116 | std::cerr << "+----" << std::endl; 117 | std::cerr << "| Error in " << filename.c_str() << ":" << *error << std::endl; 118 | std::cerr << "| (" << message->GetLineNumber() << "):" << *v8::String::Utf8Value(message->GetSourceLine()) << std::endl; 119 | std::cerr << "+----" << std::endl; 120 | return false; 121 | } 122 | 123 | // Finally we run the script 124 | v8::Handle result = script->Run(); 125 | if (result.IsEmpty()) 126 | { 127 | v8::String::Utf8Value error(tryCatch.Exception()); 128 | std::cerr << "Script Error: " << *error << std::endl; 129 | return false; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | } 136 | 137 | -------------------------------------------------------------------------------- /tests/tut/tut_exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_EXCEPTION_H_GUARD 2 | #define TUT_EXCEPTION_H_GUARD 3 | 4 | #include 5 | #include "tut_result.hpp" 6 | 7 | namespace tut 8 | { 9 | 10 | /** 11 | * The base for all TUT exceptions. 12 | */ 13 | struct tut_error : public std::exception 14 | { 15 | explicit tut_error(const std::string& msg) 16 | : err_msg(msg) 17 | { 18 | } 19 | 20 | virtual test_result::result_type result() const 21 | { 22 | return test_result::ex; 23 | } 24 | 25 | virtual std::string type() const 26 | { 27 | return "tut::tut_error"; 28 | } 29 | 30 | const char* what() const throw() 31 | { 32 | return err_msg.c_str(); 33 | } 34 | 35 | ~tut_error() throw() 36 | { 37 | } 38 | 39 | private: 40 | void operator=(const tut_error &); 41 | 42 | const std::string err_msg; 43 | }; 44 | 45 | /** 46 | * Group not found exception. 47 | */ 48 | struct no_such_group : public tut_error 49 | { 50 | explicit no_such_group(const std::string& grp) 51 | : tut_error(grp) 52 | { 53 | } 54 | 55 | virtual std::string type() const 56 | { 57 | return "tut::no_such_group"; 58 | } 59 | 60 | ~no_such_group() throw() 61 | { 62 | } 63 | }; 64 | 65 | /** 66 | * Test not found exception. 67 | */ 68 | struct no_such_test : public tut_error 69 | { 70 | explicit no_such_test(const std::string& grp) 71 | : tut_error(grp) 72 | { 73 | } 74 | 75 | virtual std::string type() const 76 | { 77 | return "tut::no_such_test"; 78 | } 79 | 80 | ~no_such_test() throw() 81 | { 82 | } 83 | }; 84 | 85 | /** 86 | * Internal exception to be throwed when 87 | * test constructor has failed. 88 | */ 89 | struct bad_ctor : public tut_error 90 | { 91 | explicit bad_ctor(const std::string& msg) 92 | : tut_error(msg) 93 | { 94 | } 95 | 96 | test_result::result_type result() const 97 | { 98 | return test_result::ex_ctor; 99 | } 100 | 101 | virtual std::string type() const 102 | { 103 | return "tut::bad_ctor"; 104 | } 105 | 106 | ~bad_ctor() throw() 107 | { 108 | } 109 | }; 110 | 111 | /** 112 | * Exception to be throwed when ensure() fails or fail() called. 113 | */ 114 | struct failure : public tut_error 115 | { 116 | explicit failure(const std::string& msg) 117 | : tut_error(msg) 118 | { 119 | } 120 | 121 | test_result::result_type result() const 122 | { 123 | return test_result::fail; 124 | } 125 | 126 | virtual std::string type() const 127 | { 128 | return "tut::failure"; 129 | } 130 | 131 | ~failure() throw() 132 | { 133 | } 134 | }; 135 | 136 | /** 137 | * Exception to be throwed when test desctructor throwed an exception. 138 | */ 139 | struct warning : public tut_error 140 | { 141 | explicit warning(const std::string& msg) 142 | : tut_error(msg) 143 | { 144 | } 145 | 146 | test_result::result_type result() const 147 | { 148 | return test_result::warn; 149 | } 150 | 151 | virtual std::string type() const 152 | { 153 | return "tut::warning"; 154 | } 155 | 156 | ~warning() throw() 157 | { 158 | } 159 | }; 160 | 161 | /** 162 | * Exception to be throwed when test issued SEH (Win32) 163 | */ 164 | struct seh : public tut_error 165 | { 166 | explicit seh(const std::string& msg) 167 | : tut_error(msg) 168 | { 169 | } 170 | 171 | virtual test_result::result_type result() const 172 | { 173 | return test_result::term; 174 | } 175 | 176 | virtual std::string type() const 177 | { 178 | return "tut::seh"; 179 | } 180 | 181 | ~seh() throw() 182 | { 183 | } 184 | }; 185 | 186 | /** 187 | * Exception to be throwed when child processes fail. 188 | */ 189 | struct rethrown : public failure 190 | { 191 | explicit rethrown(const test_result &result) 192 | : failure(result.message), tr(result) 193 | { 194 | } 195 | 196 | virtual test_result::result_type result() const 197 | { 198 | return test_result::rethrown; 199 | } 200 | 201 | virtual std::string type() const 202 | { 203 | return "tut::rethrown"; 204 | } 205 | 206 | ~rethrown() throw() 207 | { 208 | } 209 | 210 | const test_result tr; 211 | }; 212 | 213 | struct skipped : public tut_error 214 | { 215 | explicit skipped(const std::string& msg) 216 | : tut_error(msg) 217 | { 218 | } 219 | 220 | virtual test_result::result_type result() const 221 | { 222 | return test_result::skipped; 223 | } 224 | 225 | virtual std::string type() const 226 | { 227 | return "tut::skipped"; 228 | } 229 | 230 | ~skipped() throw() 231 | { 232 | } 233 | }; 234 | 235 | } 236 | 237 | #endif 238 | -------------------------------------------------------------------------------- /src/Canvas.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Canvas.h" 24 | #include "Context.h" 25 | #include "Painter.h" 26 | #include "util/Thread.h" 27 | 28 | #include 29 | #include 30 | 31 | namespace canvas 32 | { 33 | class CanvasThread : public Thread 34 | { 35 | public: 36 | CanvasThread(Painter * painter, std::string fileOrCode, bool isFile) 37 | : Thread(), 38 | m_painter(painter), 39 | m_fileOrCode(fileOrCode), 40 | m_isFile(isFile) 41 | { } 42 | 43 | void run() 44 | { 45 | m_painter->start(m_fileOrCode, m_isFile); 46 | 47 | while (m_running) 48 | { 49 | m_painter->draw(); 50 | 51 | // Sleep 1 milisecond so we don't hog all the cpu power. 52 | usleep(1000); 53 | }; 54 | } 55 | 56 | private: 57 | Painter * m_painter; 58 | std::string m_fileOrCode; 59 | bool m_isFile; 60 | }; 61 | 62 | /// Holds all private data for the Canvas class. 63 | class CanvasData 64 | { 65 | public: 66 | CanvasData() 67 | : threaded(false), 68 | started(false), 69 | painter(0), 70 | thread(0) 71 | { } 72 | 73 | ~CanvasData() 74 | { 75 | if (thread) 76 | { 77 | thread->stop(); 78 | delete thread; 79 | } 80 | 81 | delete painter; 82 | } 83 | 84 | bool threaded; 85 | bool started; 86 | Painter * painter; 87 | Thread * thread; 88 | }; 89 | 90 | 91 | Canvas::Canvas(int width, int height, Format format, bool threaded) 92 | : m_data(new CanvasData()) 93 | { 94 | m_data->threaded = threaded; 95 | m_data->painter = new Painter(width, height, format); 96 | } 97 | 98 | Canvas::Canvas(Canvas const& other) 99 | { 100 | } 101 | 102 | Canvas & Canvas::operator = (Canvas const& other) 103 | { 104 | } 105 | 106 | Canvas::~Canvas() 107 | { 108 | } 109 | 110 | bool Canvas::isDirty() const 111 | { 112 | return true; 113 | } 114 | 115 | void Canvas::paint(void * imageData) 116 | { 117 | assert(m_data->started && "Must load a javascript before any painting is performed."); 118 | 119 | if (!m_data->threaded) 120 | m_data->painter->draw(); 121 | 122 | if (imageData) 123 | m_data->painter->copyImageTo(imageData); 124 | } 125 | 126 | void Canvas::startWithFile(std::string const& filename) 127 | { 128 | assert(!m_data->started && "Only one script per canvas is allowed!"); 129 | 130 | m_data->started = true; 131 | 132 | if (m_data->threaded) 133 | m_data->thread = new CanvasThread(m_data->painter, filename, true); 134 | else 135 | m_data->painter->start(filename, true); 136 | } 137 | 138 | void Canvas::startWithCode(std::string const& code) 139 | { 140 | assert(!m_data->started && "Only one script per canvas is allowed!"); 141 | 142 | m_data->started = true; 143 | 144 | if (m_data->threaded) 145 | m_data->thread = new CanvasThread(m_data->painter, code, false); 146 | else 147 | m_data->painter->start(code, false); 148 | } 149 | 150 | void Canvas::registerImage(std::string const& name, int width, int height, Format format, void * data) 151 | { 152 | assert(m_data->painter); 153 | 154 | m_data->painter->registerImage(name, new ImageData(data, width, height, format)); 155 | } 156 | 157 | std::string Canvas::lastLogEntry() 158 | { 159 | assert(m_data->painter); 160 | return m_data->painter->lastLogEntry(); 161 | } 162 | 163 | } 164 | 165 | -------------------------------------------------------------------------------- /examples/Demo.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace canvas; 31 | 32 | /// Simple function that tries to locate the Demo.js file 33 | std::string locateDemoJavaScript() 34 | { 35 | std::string paths[3] = { 36 | "examples/Demo.js", 37 | "../examples/Demo.js", 38 | "../../examples/Demo.js" 39 | }; 40 | 41 | for (int i = 0; i < 3; ++i) 42 | { 43 | std::ifstream file(paths[i].c_str()); 44 | if (file.is_open()) 45 | return paths[i]; 46 | } 47 | 48 | return ""; 49 | } 50 | 51 | int main(int argc, char * argv[]) 52 | { 53 | bool running = true; 54 | 55 | if (argc < 2) 56 | { 57 | std::cout << "Usage: demo (-i ) " << std::endl; 58 | return 0; 59 | } 60 | 61 | if (SDL_Init(SDL_INIT_EVERYTHING) < 0) 62 | { 63 | std::cerr << "Could not initialize SDL" << std::endl; 64 | return 1; 65 | } 66 | 67 | // Create the window 68 | SDL_Surface * screen = SDL_SetVideoMode(800, 500, 32, SDL_HWSURFACE | SDL_DOUBLEBUF); 69 | SDL_WM_SetCaption("Canvas++ Demo", 0); 70 | 71 | // Create the canvas 72 | Canvas * canvas = new Canvas(800, 500, Canvas::kRGBA, true); 73 | 74 | // Parse arguments 75 | for (int i = 1; i < argc; ++i) 76 | { 77 | std::string arg(argv[i]); 78 | if (arg == "-i" && (i + 1) < argc) 79 | { 80 | SDL_Surface * image = IMG_Load(argv[i + 1]); 81 | if (!image) 82 | { 83 | std::cerr << "Could not load image: " << argv[i + 1] << std::endl; 84 | } 85 | else 86 | { 87 | if (image->format->BitsPerPixel == 32) 88 | { 89 | std::cerr << "Loaded image (" << image->w << "x" << image->h << "): " << argv[i + 1] << std::endl; 90 | canvas->registerImage(argv[i + 1], image->w, image->h, Canvas::kRGBA, image->pixels); 91 | } 92 | else 93 | { 94 | std::cerr << "Image '" << argv[i + 1] << "' has the wrong format (" << (int)image->format->BitsPerPixel << ")" << std::endl; 95 | } 96 | 97 | SDL_FreeSurface(image); 98 | } 99 | 100 | i++; 101 | } 102 | } 103 | 104 | // Last argument must be the script file 105 | canvas->startWithFile(argv[argc - 1]); 106 | 107 | // Create a sdl surface that will act like a target for the canvas 108 | SDL_Surface * target = SDL_CreateRGBSurface(SDL_SWSURFACE, 800, 500, 32, 0x00FF0000, 109 | 0x0000FF00, 110 | 0x000000FF, 111 | 0xFF000000); 112 | 113 | // Enter the application loop 114 | while (running) 115 | { 116 | SDL_Event event; 117 | while (SDL_PollEvent(&event)) 118 | { 119 | switch (event.type) 120 | { 121 | case SDL_QUIT: 122 | running = false; 123 | break; 124 | case SDL_KEYDOWN: 125 | switch (event.key.keysym.sym) 126 | { 127 | case SDLK_ESCAPE: 128 | running = false; 129 | break; 130 | } 131 | break; 132 | } 133 | } 134 | 135 | if (canvas->isDirty()) 136 | { 137 | SDL_LockSurface(target); 138 | canvas->paint(target->pixels); 139 | SDL_UnlockSurface(target); 140 | } 141 | 142 | SDL_BlitSurface(target, 0, screen, 0); 143 | 144 | // Print log 145 | for (std::string log = canvas->lastLogEntry(); log != ""; log = canvas->lastLogEntry()) 146 | //while ((std::string log = canvas->lastLogEntry()) != "") 147 | std::cout << log << std::endl; 148 | 149 | SDL_Flip(screen); 150 | SDL_Delay(10); 151 | } 152 | 153 | delete canvas; 154 | 155 | SDL_FreeSurface(screen); 156 | SDL_Quit(); 157 | 158 | return 0; 159 | } -------------------------------------------------------------------------------- /src/binding/FunctionInfo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef V8_SCRIPT_FUNCTION_INFO_HPP 24 | #define V8_SCRIPT_FUNCTION_INFO_HPP 25 | 26 | #include "Types.h" 27 | #include "TypeList.h" 28 | 29 | namespace binding { 30 | 31 | template 32 | struct FunctionInfo; 33 | 34 | 35 | template 36 | struct FunctionInfo 37 | { 38 | typedef O Object; 39 | typedef R Return; 40 | typedef NullType Params; 41 | 42 | static const bool Const = false; 43 | }; 44 | 45 | template 46 | struct FunctionInfo 47 | { 48 | typedef O Object; 49 | typedef R Return; 50 | typedef TYPELIST_1(P1) Params; 51 | 52 | static const bool Const = false; 53 | }; 54 | 55 | template 56 | struct FunctionInfo 57 | { 58 | typedef O Object; 59 | typedef R Return; 60 | typedef TYPELIST_2(P1, P2) Params; 61 | 62 | static const bool Const = false; 63 | }; 64 | 65 | template 66 | struct FunctionInfo 67 | { 68 | typedef O Object; 69 | typedef R Return; 70 | typedef TYPELIST_3(P1, P2, P3) Params; 71 | 72 | static const bool Const = false; 73 | }; 74 | 75 | template 76 | struct FunctionInfo 77 | { 78 | typedef O Object; 79 | typedef R Return; 80 | typedef TYPELIST_4(P1, P2, P3, P4) Params; 81 | 82 | static const bool Const = false; 83 | }; 84 | 85 | template 86 | struct FunctionInfo 87 | { 88 | typedef O Object; 89 | typedef R Return; 90 | typedef TYPELIST_5(P1, P2, P3, P4, P5) Params; 91 | 92 | static const bool Const = false; 93 | }; 94 | 95 | template 96 | struct FunctionInfo 97 | { 98 | typedef O Object; 99 | typedef R Return; 100 | typedef TYPELIST_6(P1, P2, P3, P4, P5, P6) Params; 101 | 102 | static const bool Const = false; 103 | }; 104 | 105 | 106 | // - Const definitions 107 | 108 | template 109 | struct FunctionInfo 110 | { 111 | typedef O Object; 112 | typedef R Return; 113 | typedef NullType Params; 114 | 115 | static const bool Const = true; 116 | }; 117 | 118 | template 119 | struct FunctionInfo 120 | { 121 | typedef O Object; 122 | typedef R Return; 123 | typedef TYPELIST_1(P1) Params; 124 | 125 | static const bool Const = true; 126 | }; 127 | 128 | template 129 | struct FunctionInfo 130 | { 131 | typedef O Object; 132 | typedef R Return; 133 | typedef TYPELIST_2(P1, P2) Params; 134 | 135 | static const bool Const = true; 136 | }; 137 | 138 | template 139 | struct FunctionInfo 140 | { 141 | typedef O Object; 142 | typedef R Return; 143 | typedef TYPELIST_3(P1, P2, P3) Params; 144 | 145 | static const bool Const = true; 146 | }; 147 | 148 | template 149 | struct FunctionInfo 150 | { 151 | typedef O Object; 152 | typedef R Return; 153 | typedef TYPELIST_4(P1, P2, P3, P4) Params; 154 | 155 | static const bool Const = true; 156 | }; 157 | 158 | template 159 | struct FunctionInfo 160 | { 161 | typedef O Object; 162 | typedef R Return; 163 | typedef TYPELIST_5(P1, P2, P3, P4, P5) Params; 164 | 165 | static const bool Const = true; 166 | }; 167 | 168 | template 169 | struct FunctionInfo 170 | { 171 | typedef O Object; 172 | typedef R Return; 173 | typedef TYPELIST_6(P1, P2, P3, P4, P5, P6) Params; 174 | 175 | static const bool Const = true; 176 | }; 177 | 178 | } 179 | 180 | #endif 181 | 182 | -------------------------------------------------------------------------------- /tests/tut/tut_fpt.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief Additional ensures for scientific/engineering applications. 3 | * @author Joerg 4 | * @date 07/04/2008 5 | */ 6 | #ifndef TUT_Float_H_GUARD 7 | #define TUT_Float_H_GUARD 8 | 9 | #include 10 | #include 11 | 12 | namespace tut 13 | { 14 | namespace detail 15 | { 16 | template 17 | struct If 18 | { 19 | typedef Else type; 20 | }; 21 | 22 | template 23 | struct If 24 | { 25 | typedef Then type; 26 | }; 27 | 28 | template 29 | struct fpt_traits 30 | { 31 | struct StdNumericLimitsNotAvailable {}; 32 | static const StdNumericLimitsNotAvailable static_check[ std::numeric_limits::is_specialized ]; 33 | 34 | static const T zero; 35 | 36 | typedef typename If::is_integer, 37 | double, 38 | T>::type Result; 39 | 40 | static T abs(const T &arg) 41 | { 42 | if(arg < zero) 43 | return zero - arg; 44 | else 45 | return arg; 46 | } 47 | 48 | static T sig(const T &arg) 49 | { 50 | if(arg < zero) 51 | return -1; 52 | else 53 | return 1; 54 | } 55 | 56 | static inline Result div(const Result &number, const T &divisor) 57 | { 58 | static_cast(static_check); 59 | 60 | if(number == zero && divisor == zero) 61 | return std::numeric_limits::quiet_NaN(); 62 | 63 | if(number == zero) 64 | return zero; 65 | 66 | if(divisor == zero) 67 | return sig(number) * std::numeric_limits::infinity(); 68 | 69 | assert(zero < number); 70 | assert(zero < divisor); 71 | 72 | // Avoid underflow 73 | if(static_cast(1) < abs(divisor)) 74 | { 75 | // number / divisor < min <=> number < min * divisor 76 | if( abs(number) < abs(divisor) * std::numeric_limits::min()) 77 | { 78 | return sig(divisor) * sig(number) * std::numeric_limits::min(); 79 | } 80 | } 81 | 82 | // Avoid overflow 83 | if( abs(divisor) < static_cast(1)) 84 | { 85 | // number / divisor > max <=> number > max * divisor 86 | if( abs(divisor) * std::numeric_limits::max() < abs(number)) 87 | { 88 | return sig(divisor) * sig(number) * std::numeric_limits::max(); 89 | } 90 | } 91 | 92 | return number / divisor; 93 | } 94 | }; 95 | 96 | template 97 | const typename fpt_traits::StdNumericLimitsNotAvailable 98 | fpt_traits::static_check[ std::numeric_limits::is_specialized ] = { {} }; 99 | 100 | template 101 | const T fpt_traits::zero = static_cast(0); 102 | 103 | template 104 | bool check_tolerance(T actual, T expected, U fraction) 105 | { 106 | typename fpt_traits::Result diff = fpt_traits::div( fpt_traits::abs( expected - actual ), 107 | fpt_traits::abs( expected ) ); 108 | 109 | return (diff == fraction) || (diff < fraction); 110 | } 111 | 112 | } // namespace detail 113 | 114 | template 115 | void ensure_close(const char* msg, const T& actual, const T& expected, const U& tolerance ) 116 | { 117 | typedef detail::fpt_traits Traits; 118 | 119 | typename Traits::Result fraction = Traits::div( Traits::abs(static_cast(tolerance)), 120 | static_cast(100) ); 121 | if( !detail::check_tolerance(actual, expected, fraction) ) 122 | { 123 | std::ostringstream ss; 124 | ss << ( msg ? msg : "" ) 125 | << ( msg ? ": " : "" ) 126 | << "expected `" 127 | << expected 128 | << "` and actual `" 129 | << actual 130 | << "` differ more than " 131 | << tolerance 132 | << "%"; 133 | throw failure( ss.str().c_str() ); 134 | } 135 | } 136 | 137 | template 138 | void ensure_close(const T& actual, const T& expected, const Tolerance& tolerance ) 139 | { 140 | ensure_close( 0, actual, expected, tolerance ); 141 | } 142 | 143 | template 144 | void ensure_close_fraction(const char* msg, const T& actual, const T& expected, const U& fraction) 145 | { 146 | typedef char StdNumericLimitsNotAvailable; 147 | const StdNumericLimitsNotAvailable static_check[ std::numeric_limits::is_specialized ] = { 0 }; 148 | static_cast(static_check); 149 | 150 | typedef typename detail::If::is_integer, 151 | double, 152 | U>::type Tolerance; 153 | 154 | if( !detail::check_tolerance(actual, expected, fraction) ) 155 | { 156 | std::ostringstream ss; 157 | ss << ( msg ? msg : "" ) 158 | << ( msg ? ": " : "" ) 159 | << "expected `" 160 | << expected 161 | << "` and actual `" 162 | << actual 163 | << "` differ more than fraction `" 164 | << fraction 165 | << "`"; 166 | throw failure( ss.str().c_str() ); 167 | } 168 | } 169 | 170 | template 171 | void ensure_close_fraction( const char* msg, const T& actual, const T& expected, const int& tolerance ) 172 | { 173 | ensure_close(msg, actual, expected, double(tolerance)); 174 | } 175 | 176 | template< typename T, typename Tolerance> 177 | void ensure_close_fraction(const T& actual, const T& expected, const Tolerance& fraction) 178 | { 179 | ensure_close_fraction( 0, actual, expected, fraction ); 180 | } 181 | 182 | } // namespace tut 183 | 184 | #endif 185 | 186 | -------------------------------------------------------------------------------- /src/binding/Object.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef V8_SCRIPT_OBJECT_HPP 24 | #define V8_SCRIPT_OBJECT_HPP 25 | 26 | #include "v8.h" 27 | #include 28 | #include 29 | #include 30 | 31 | #include "Function.h" 32 | #include "Attribute.h" 33 | #include "FunctionInfo.h" 34 | 35 | namespace binding { 36 | 37 | extern v8::Handle scriptCallback(v8::Arguments const& args); 38 | extern v8::Handle scriptConstructor(v8::Arguments const& args); 39 | 40 | extern void attributeSetCallback(v8::Local name, v8::Local value, v8::AccessorInfo const& info); 41 | extern v8::Handle attributeGetCallback(v8::Local name, v8::AccessorInfo const& info); 42 | 43 | 44 | template 45 | class Object 46 | { 47 | public: 48 | 49 | /// Copy constructor 50 | Object(Object const& other) 51 | { 52 | m_functionTemplate = v8::Persistent::New(other.m_functionTemplate); 53 | } 54 | 55 | Object(std::string const& name) 56 | { 57 | v8::Handle functionTemplate = v8::FunctionTemplate::New(&scriptConstructor); 58 | functionTemplate->SetClassName(v8::String::New(name.c_str())); 59 | functionTemplate->InstanceTemplate()->SetInternalFieldCount(1); 60 | 61 | m_functionTemplate = v8::Persistent::New(functionTemplate); 62 | } 63 | 64 | v8::Handle getFunction() 65 | { 66 | return m_functionTemplate; 67 | } 68 | 69 | template 70 | Object & function(std::string const& name, Fun func) 71 | { 72 | addCallback(name, new binding::Functor::Return, typename FunctionInfo::Params>(func)); 73 | return *this; 74 | } 75 | 76 | /// Make it posible to bind 'ordinary' v8 callback functions. 77 | Object & functionV8(std::string const& name, v8::InvocationCallback callback) 78 | { 79 | v8::Handle protoTempl = m_functionTemplate->PrototypeTemplate(); 80 | protoTempl->Set(v8::String::New(name.c_str()), v8::FunctionTemplate::New(callback)); 81 | 82 | return *this; 83 | } 84 | 85 | template 86 | Object & attribute(std::string const& name, AttribT T::*ptr) 87 | { 88 | v8::Handle instaTempl = m_functionTemplate->InstanceTemplate(); 89 | 90 | BaseAttribute * attrib = new AttributePtr(ptr); 91 | 92 | instaTempl->SetAccessor(v8::String::New(name.c_str()), 93 | attributeGetCallback, 94 | attributeSetCallback, 95 | v8::External::Wrap(attrib)); 96 | return *this; 97 | } 98 | 99 | template 100 | Object & attribute(std::string const& name, GetT get, SetT set) 101 | { 102 | v8::Handle instaTempl = m_functionTemplate->InstanceTemplate(); 103 | 104 | BaseAttribute * attrib = new AttributeCallback(get, set); 105 | 106 | instaTempl->SetAccessor(v8::String::New(name.c_str()), 107 | attributeGetCallback, 108 | attributeSetCallback, 109 | v8::External::Wrap(attrib)); 110 | return *this; 111 | } 112 | 113 | template 114 | Object & getter(std::string const& name, AttribT T::*ptr) 115 | { 116 | v8::Handle instaTempl = m_functionTemplate->InstanceTemplate(); 117 | 118 | BaseAttribute * attrib = new AttributePtr(ptr); 119 | 120 | instaTempl->SetAccessor(v8::String::New(name.c_str()), 121 | attributeGetCallback, 122 | 0, 123 | v8::External::Wrap(attrib)); 124 | return *this; 125 | } 126 | 127 | /** 128 | * Transform an object from C++ to Javascript. 129 | */ 130 | v8::Handle wrap(T * object) 131 | { 132 | v8::HandleScope scope; 133 | 134 | //if (!object) 135 | // scope.Close(v8::Undefined()); 136 | 137 | v8::Local result = m_functionTemplate->GetFunction()->NewInstance(); 138 | result->SetInternalField(0, v8::External::New(object)); 139 | 140 | return scope.Close(result); 141 | } 142 | 143 | /** 144 | * Transform a Javascript object to C++. 145 | */ 146 | static inline T * unwrap(v8::Local obj) 147 | { 148 | v8::HandleScope scope; 149 | v8::Local field = v8::Local::Cast(obj->GetInternalField(0)); 150 | void* ptr = field->Value(); 151 | return static_cast(ptr); 152 | } 153 | 154 | private: 155 | void addCallback(std::string const& name, binding::BaseFunctor * functor) 156 | { 157 | v8::Handle protoTempl = m_functionTemplate->PrototypeTemplate(); 158 | protoTempl->Set(v8::String::New(name.c_str()), v8::FunctionTemplate::New(&scriptCallback, v8::External::Wrap(functor))); 159 | } 160 | 161 | private: 162 | v8::Persistent m_functionTemplate; 163 | }; 164 | 165 | } 166 | 167 | #endif 168 | 169 | -------------------------------------------------------------------------------- /src/ColorParser.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "ColorParser.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace canvas 30 | { 31 | 32 | ColorParser::ColorParser() 33 | { 34 | // Insert some standard colors 35 | m_cached.insert(std::make_pair("black", Color(0, 0, 0))); 36 | m_cached.insert(std::make_pair("white", Color(255, 255, 255))); 37 | m_cached.insert(std::make_pair("red", Color(255, 0, 0))); 38 | m_cached.insert(std::make_pair("lime", Color(0, 255, 0))); 39 | m_cached.insert(std::make_pair("blue", Color(0, 0, 255))); 40 | m_cached.insert(std::make_pair("green", Color(0, 255, 0))); 41 | m_cached.insert(std::make_pair("grey", Color(128, 128, 128))); 42 | m_cached.insert(std::make_pair("lightgrey", Color(211, 211, 211))); 43 | m_cached.insert(std::make_pair("lightblue", Color(173,216,230))); 44 | m_cached.insert(std::make_pair("lightgreen", Color(144,238,144))); 45 | m_cached.insert(std::make_pair("orange", Color(255,165,0))); 46 | m_cached.insert(std::make_pair("orangered", Color(255,69,0))); 47 | m_cached.insert(std::make_pair("skyblue", Color(135,206,235))); 48 | m_cached.insert(std::make_pair("yellow", Color(255,255,0))); 49 | m_cached.insert(std::make_pair("pink", Color(255,192,203))); 50 | m_cached.insert(std::make_pair("indigo", Color(75,0,130))); 51 | } 52 | 53 | Color ColorParser::parse(std::string const& color) 54 | { 55 | Color resultColor; 56 | 57 | ColorMap::iterator search = m_cached.find(color); 58 | if (search != m_cached.end()) 59 | { 60 | resultColor = search->second; 61 | } 62 | else 63 | { 64 | // Parse the color string 65 | using namespace boost::xpressive; 66 | 67 | // Matches: rgb(, , ) 68 | sregex rgbFunc = "rgb(" >> *space >> (s1= +_d) >> *space >> ',' >> *space >> (s2= +_d) >> *space >> ',' >> *space >> (s3= +_d) >> *space >> ')'; 69 | 70 | // Matches: rgba(, , , ) 71 | sregex rgbaFunc = "rgba(" >> *space >> (s1= +_d) >> *space >> ',' >> *space >> 72 | (s2= +_d) >> *space >> ',' >> *space >> 73 | (s3= +_d) >> *space >> ',' >> *space >> 74 | (s4= +_d >> '.' >> +_d) >> *space >> ')'; 75 | 76 | sregex hex = (_d | (set= 'a','b','c','d','e','f', 'A', 'B', 'C', 'D', 'E', 'F')); 77 | // Matches #rgb 78 | sregex rgbHex = '#' >> (s1= hex) >> 79 | (s2= hex) >> 80 | (s3= hex); 81 | // Matches: #rrggbb 82 | sregex rrggbbHex = '#' >> (s1= hex >> hex) >> 83 | (s2= hex >> hex) >> 84 | (s3= hex >> hex); 85 | 86 | smatch result; 87 | if (regex_match(color, result, rgbFunc)) 88 | { 89 | resultColor = Color(boost::lexical_cast(result.str(1)) / 255.0f, 90 | boost::lexical_cast(result.str(2)) / 255.0f, 91 | boost::lexical_cast(result.str(3)) / 255.0f, 92 | 1.0f); 93 | 94 | m_cached.insert(std::make_pair(color, resultColor)); 95 | } 96 | else if (regex_match(color, result, rgbaFunc)) 97 | { 98 | resultColor = Color(boost::lexical_cast(result.str(1)) / 255.0f, 99 | boost::lexical_cast(result.str(2)) / 255.0f, 100 | boost::lexical_cast(result.str(3)) / 255.0f, 101 | boost::lexical_cast(result.str(4))); 102 | 103 | m_cached.insert(std::make_pair(color, resultColor)); 104 | } 105 | else if (regex_match(color, result, rrggbbHex)) 106 | { 107 | resultColor = Color(hexStringToInt(result.str(1)) / 255.0f, 108 | hexStringToInt(result.str(2)) / 255.0f, 109 | hexStringToInt(result.str(3)) / 255.0f, 110 | 1.0f); 111 | 112 | m_cached.insert(std::make_pair(color, resultColor)); 113 | } 114 | else if (regex_match(color, result, rgbHex)) 115 | { 116 | std::string r = result.str(1); 117 | std::string g = result.str(2); 118 | std::string b = result.str(3); 119 | 120 | r = r.size() == 1 ? r + r : r; 121 | g = g.size() == 1 ? g + g : g; 122 | b = b.size() == 1 ? b + b : b; 123 | 124 | resultColor = Color(hexStringToInt(r) / 255.0f, 125 | hexStringToInt(g) / 255.0f, 126 | hexStringToInt(b) / 255.0f, 127 | 1.0f); 128 | 129 | m_cached.insert(std::make_pair(color, resultColor)); 130 | } 131 | else 132 | std::cerr << "Invalid color: " << color << std::endl; 133 | } 134 | 135 | return resultColor; 136 | } 137 | 138 | int ColorParser::hexStringToInt(std::string const& str) 139 | { 140 | int result = 0; 141 | 142 | std::string::const_iterator it = str.begin(); 143 | std::string::const_iterator end = str.end(); 144 | for (; it != end; ++it) 145 | { 146 | result = result << 4; 147 | char c = *it; 148 | 149 | if (c >= '0' && c <= '9') 150 | result += c - '0'; 151 | else if (c >= 'a' && c <= 'f') 152 | result += 10 + (c - 'a'); 153 | else if (c >= 'A' && c <= 'F') 154 | result += 10 + (c - 'A'); 155 | } 156 | return result; 157 | } 158 | 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/binding/Translate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | /** 23 | * The Translate struct is used to transform ordinary datatypes to and from 24 | * thier javascript counterparts. 25 | */ 26 | 27 | #ifndef V8_SCRIPT_TRANSLATE_HPP 28 | #define V8_SCRIPT_TRANSLATE_HPP 29 | 30 | #include "v8.h" 31 | #include 32 | #include 33 | 34 | #include "Types.h" 35 | 36 | namespace binding { 37 | 38 | // Forward declarations 39 | template class Object; 40 | 41 | template struct Translate; 42 | 43 | template <> 44 | struct Translate 45 | { 46 | static EmptyType to(v8::Handle const& value) 47 | { 48 | return EmptyType(); 49 | } 50 | }; 51 | 52 | template <> 53 | struct Translate 54 | { 55 | static bool to(v8::Handle const& value) 56 | { 57 | return value->BooleanValue(); 58 | } 59 | 60 | static v8::Handle from(bool value) 61 | { 62 | return v8::Boolean::New(value); 63 | } 64 | }; 65 | 66 | template <> 67 | struct Translate 68 | { 69 | static char to(v8::Handle const& value) 70 | { 71 | return value->Int32Value(); 72 | } 73 | 74 | static v8::Handle from(char value) 75 | { 76 | return v8::Int32::New(value); 77 | } 78 | }; 79 | 80 | template <> 81 | struct Translate 82 | { 83 | static unsigned char to(v8::Handle const& value) 84 | { 85 | return value->Uint32Value(); 86 | } 87 | 88 | static v8::Handle from(unsigned char value) 89 | { 90 | return v8::Uint32::New(value); 91 | } 92 | }; 93 | 94 | template <> 95 | struct Translate 96 | { 97 | static short to(v8::Handle const& value) 98 | { 99 | return value->Int32Value(); 100 | } 101 | 102 | static v8::Handle from(short value) 103 | { 104 | return v8::Int32::New(value); 105 | } 106 | }; 107 | 108 | template <> 109 | struct Translate 110 | { 111 | static unsigned short to(v8::Handle const& value) 112 | { 113 | return value->Uint32Value(); 114 | } 115 | 116 | static v8::Handle from(unsigned short value) 117 | { 118 | return v8::Uint32::New(value); 119 | } 120 | }; 121 | 122 | template <> 123 | struct Translate 124 | { 125 | static int to(v8::Handle const& value) 126 | { 127 | return value->Int32Value(); 128 | } 129 | 130 | static v8::Handle from(int value) 131 | { 132 | return v8::Int32::New(value); 133 | } 134 | }; 135 | 136 | template <> 137 | struct Translate 138 | { 139 | static unsigned int to(v8::Handle const& value) 140 | { 141 | return value->Uint32Value(); 142 | } 143 | 144 | static v8::Handle from(unsigned int value) 145 | { 146 | return v8::Uint32::New(value); 147 | } 148 | }; 149 | 150 | template <> 151 | struct Translate 152 | { 153 | static long to(v8::Handle const& value) 154 | { 155 | return value->Int32Value(); 156 | } 157 | 158 | static v8::Handle from(long value) 159 | { 160 | return v8::Int32::New(value); 161 | } 162 | }; 163 | 164 | template <> 165 | struct Translate 166 | { 167 | static unsigned long to(v8::Handle const& value) 168 | { 169 | return value->Uint32Value(); 170 | } 171 | 172 | static v8::Handle from(unsigned long value) 173 | { 174 | return v8::Uint32::New(value); 175 | } 176 | }; 177 | 178 | template <> 179 | struct Translate 180 | { 181 | static float to(v8::Handle const& value) 182 | { 183 | return value->NumberValue(); 184 | } 185 | 186 | static v8::Handle from(float value) 187 | { 188 | return v8::Number::New(value); 189 | } 190 | }; 191 | 192 | template <> 193 | struct Translate 194 | { 195 | static double to(v8::Handle const& value) 196 | { 197 | return value->NumberValue(); 198 | } 199 | 200 | static v8::Handle from(double value) 201 | { 202 | return v8::Number::New(value); 203 | } 204 | }; 205 | 206 | template <> 207 | struct Translate 208 | { 209 | static std::string to(v8::Handle const& value) 210 | { 211 | return *v8::String::Utf8Value(value); 212 | } 213 | 214 | static v8::Handle from(std::string const& value) 215 | { 216 | return v8::String::New(value.c_str()); 217 | } 218 | }; 219 | 220 | template <> 221 | struct Translate 222 | { 223 | static std::string to(v8::Handle const& value) 224 | { 225 | return *v8::String::Utf8Value(value); 226 | } 227 | 228 | static v8::Handle from(std::string const& value) 229 | { 230 | return v8::String::New(value.c_str()); 231 | } 232 | }; 233 | 234 | template <> 235 | struct Translate > 236 | { 237 | static v8::Handle to(v8::Handle const& value) 238 | { 239 | assert(value->IsFunction()); 240 | return v8::Handle::Cast(value); 241 | } 242 | 243 | static v8::Handle from(v8::Handle const& value) 244 | { 245 | return value; 246 | } 247 | }; 248 | 249 | template <> 250 | struct Translate const&> 251 | { 252 | static v8::Handle to(v8::Handle const& value) 253 | { 254 | assert(value->IsFunction()); 255 | return v8::Handle::Cast(value); 256 | } 257 | 258 | static v8::Handle from(v8::Handle const& value) 259 | { 260 | return value; 261 | } 262 | }; 263 | 264 | template <> 265 | struct Translate > 266 | { 267 | static v8::Handle to(v8::Handle const& value) 268 | { 269 | return value; 270 | } 271 | 272 | static v8::Handle from(v8::Handle const& value) 273 | { 274 | return value; 275 | } 276 | }; 277 | 278 | } 279 | 280 | #endif 281 | 282 | -------------------------------------------------------------------------------- /tests/tut/tut_console_reporter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_CONSOLE_REPORTER 2 | #define TUT_CONSOLE_REPORTER 3 | #include 4 | #include 5 | 6 | /** 7 | * Template Unit Tests Framework for C++. 8 | * http://tut.dozen.ru 9 | * 10 | * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com 11 | */ 12 | namespace 13 | { 14 | 15 | std::ostream& operator<<(std::ostream& os, const tut::test_result& tr) 16 | { 17 | switch(tr.result) 18 | { 19 | case tut::test_result::ok: 20 | os << '.'; 21 | break; 22 | case tut::test_result::fail: 23 | os << '[' << tr.test << "=F]"; 24 | break; 25 | case tut::test_result::ex_ctor: 26 | os << '[' << tr.test << "=C]"; 27 | break; 28 | case tut::test_result::ex: 29 | os << '[' << tr.test << "=X]"; 30 | break; 31 | case tut::test_result::warn: 32 | os << '[' << tr.test << "=W]"; 33 | break; 34 | case tut::test_result::term: 35 | os << '[' << tr.test << "=T]"; 36 | break; 37 | case tut::test_result::rethrown: 38 | os << '[' << tr.test << "=P]"; 39 | break; 40 | case tut::test_result::skipped: 41 | os << '[' << tr.test << "=S]"; 42 | break; 43 | case tut::test_result::dummy: 44 | throw tut::tut_error("console reporter called for dummy test result"); 45 | } 46 | 47 | return os; 48 | } 49 | 50 | } // end of namespace 51 | 52 | namespace tut 53 | { 54 | 55 | /** 56 | * Default TUT callback handler. 57 | */ 58 | class console_reporter : public tut::callback 59 | { 60 | std::string current_group; 61 | typedef std::vector not_passed_list; 62 | not_passed_list not_passed; 63 | std::ostream& os; 64 | 65 | console_reporter(const console_reporter &); 66 | console_reporter &operator=(const console_reporter &); 67 | public: 68 | 69 | int ok_count; 70 | int exceptions_count; 71 | int failures_count; 72 | int terminations_count; 73 | int warnings_count; 74 | int skipped_count; 75 | 76 | console_reporter() 77 | : current_group(), 78 | not_passed(), 79 | os(std::cout), 80 | ok_count(0), 81 | exceptions_count(0), 82 | failures_count(0), 83 | terminations_count(0), 84 | warnings_count(0), 85 | skipped_count(0) 86 | { 87 | init(); 88 | } 89 | 90 | console_reporter(std::ostream& out) 91 | : current_group(), 92 | not_passed(), 93 | os(out), 94 | ok_count(0), 95 | exceptions_count(0), 96 | failures_count(0), 97 | terminations_count(0), 98 | warnings_count(0), 99 | skipped_count(0) 100 | 101 | { 102 | init(); 103 | } 104 | 105 | void run_started() 106 | { 107 | init(); 108 | } 109 | 110 | void test_completed(const tut::test_result& tr) 111 | { 112 | if (tr.group != current_group) 113 | { 114 | os << std::endl << tr.group << ": " << std::flush; 115 | current_group = tr.group; 116 | } 117 | 118 | os << tr << std::flush; 119 | 120 | // update global statistics 121 | switch (tr.result) { 122 | case test_result::ok: 123 | ok_count++; 124 | break; 125 | case test_result::fail: 126 | case test_result::rethrown: 127 | failures_count++; 128 | break; 129 | case test_result::ex: 130 | case test_result::ex_ctor: 131 | exceptions_count++; 132 | break; 133 | case test_result::warn: 134 | warnings_count++; 135 | break; 136 | case test_result::term: 137 | terminations_count++; 138 | break; 139 | case test_result::skipped: 140 | skipped_count++; 141 | break; 142 | case tut::test_result::dummy: 143 | assert( (tr.result != tut::test_result::dummy) && "Should never be called"); 144 | } // switch 145 | 146 | if ( (tr.result != tut::test_result::ok) && 147 | (tr.result != tut::test_result::skipped) ) 148 | { 149 | not_passed.push_back(tr); 150 | } 151 | } 152 | 153 | void run_completed() 154 | { 155 | os << std::endl; 156 | 157 | if (not_passed.size() > 0) 158 | { 159 | not_passed_list::const_iterator i = not_passed.begin(); 160 | while (i != not_passed.end()) 161 | { 162 | tut::test_result tr = *i; 163 | 164 | os << std::endl; 165 | 166 | os << "---> " << "group: " << tr.group 167 | << ", test: test<" << tr.test << ">" 168 | << (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string()) 169 | << std::endl; 170 | 171 | #if defined(TUT_USE_POSIX) 172 | if(tr.pid != getpid()) 173 | { 174 | os << " child pid: " << tr.pid << std::endl; 175 | } 176 | #endif 177 | os << " problem: "; 178 | switch(tr.result) 179 | { 180 | case test_result::rethrown: 181 | os << "assertion failed in child" << std::endl; 182 | break; 183 | case test_result::fail: 184 | os << "assertion failed" << std::endl; 185 | break; 186 | case test_result::ex: 187 | case test_result::ex_ctor: 188 | os << "unexpected exception" << std::endl; 189 | if( tr.exception_typeid != "" ) 190 | { 191 | os << " exception typeid: " 192 | << tr.exception_typeid << std::endl; 193 | } 194 | break; 195 | case test_result::term: 196 | os << "would be terminated" << std::endl; 197 | break; 198 | case test_result::warn: 199 | os << "test passed, but cleanup code (destructor) raised" 200 | " an exception" << std::endl; 201 | break; 202 | default: 203 | break; 204 | } 205 | 206 | if (!tr.message.empty()) 207 | { 208 | if (tr.result == test_result::fail) 209 | { 210 | os << " failed assertion: `" << tr.message << "`" 211 | << std::endl; 212 | } 213 | else 214 | { 215 | os << " message: `" << tr.message << "`" 216 | << std::endl; 217 | } 218 | } 219 | 220 | ++i; 221 | } 222 | } 223 | 224 | os << std::endl; 225 | 226 | os << "tests summary:"; 227 | if (terminations_count > 0) 228 | { 229 | os << " terminations:" << terminations_count; 230 | } 231 | if (exceptions_count > 0) 232 | { 233 | os << " exceptions:" << exceptions_count; 234 | } 235 | if (failures_count > 0) 236 | { 237 | os << " failures:" << failures_count; 238 | } 239 | if (warnings_count > 0) 240 | { 241 | os << " warnings:" << warnings_count; 242 | } 243 | 244 | os << " ok:" << ok_count; 245 | 246 | if(skipped_count > 0) 247 | { 248 | os << " skipped:" << skipped_count; 249 | } 250 | os << std::endl; 251 | } 252 | 253 | virtual bool all_ok() const 254 | { 255 | return not_passed.empty(); 256 | } 257 | 258 | private: 259 | 260 | void init() 261 | { 262 | ok_count = 0; 263 | exceptions_count = 0; 264 | failures_count = 0; 265 | terminations_count = 0; 266 | warnings_count = 0; 267 | skipped_count = 0; 268 | not_passed.clear(); 269 | } 270 | }; 271 | 272 | } 273 | 274 | #endif 275 | -------------------------------------------------------------------------------- /tests/tut/tut_assert.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_ASSERT_H_GUARD 2 | #define TUT_ASSERT_H_GUARD 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(TUT_USE_POSIX) 12 | #include 13 | #include 14 | #endif 15 | 16 | #include "tut_exception.hpp" 17 | 18 | namespace tut 19 | { 20 | 21 | namespace detail 22 | { 23 | template 24 | std::ostringstream &msg_prefix(std::ostringstream &str, const M &msg) 25 | { 26 | std::ostringstream ss; 27 | ss << msg; 28 | 29 | if(!ss.str().empty()) 30 | { 31 | str << msg << ": "; 32 | } 33 | 34 | return str; 35 | } 36 | } 37 | 38 | 39 | namespace 40 | { 41 | 42 | /** 43 | * Tests provided condition. 44 | * Throws if false. 45 | */ 46 | void ensure(bool cond) 47 | { 48 | if (!cond) 49 | { 50 | // TODO: default ctor? 51 | throw failure(""); 52 | } 53 | } 54 | 55 | /** 56 | * Tests provided condition. 57 | * Throws if true. 58 | */ 59 | void ensure_not(bool cond) 60 | { 61 | ensure(!cond); 62 | } 63 | 64 | /** 65 | * Tests provided condition. 66 | * Throws if false. 67 | */ 68 | template 69 | void ensure(const M& msg, bool cond) 70 | { 71 | if (!cond) 72 | { 73 | throw failure(msg); 74 | } 75 | } 76 | 77 | /** 78 | * Tests provided condition. 79 | * Throws if true. 80 | */ 81 | template 82 | void ensure_not(const M& msg, bool cond) 83 | { 84 | ensure(msg, !cond); 85 | } 86 | 87 | /** 88 | * Tests two objects for being equal. 89 | * Throws if false. 90 | * 91 | * NB: both LHS and RHS must have operator << defined somewhere, or 92 | * client code will not compile at all! 93 | */ 94 | template 95 | void ensure_equals(const M& msg, const LHS& actual, const RHS& expected) 96 | { 97 | if (expected != actual) 98 | { 99 | std::ostringstream ss; 100 | detail::msg_prefix(ss,msg) 101 | << "expected `" 102 | << expected 103 | << "` actual `" 104 | << actual 105 | << "`"; 106 | throw failure(ss.str()); 107 | } 108 | } 109 | 110 | /** 111 | * Tests two pointers for being equal. 112 | * Throws if false. 113 | * 114 | * NB: both T and Q must have operator << defined somewhere, or 115 | * client code will not compile at all! 116 | */ 117 | template 118 | void ensure_equals(const M& msg, const LHS * const actual, const RHS * const expected) 119 | { 120 | if (expected != actual) 121 | { 122 | std::ostringstream ss; 123 | detail::msg_prefix(ss,msg) 124 | << "expected `" 125 | << (void*)expected 126 | << "` actual `" 127 | << (void*)actual 128 | << "`"; 129 | throw failure(ss.str()); 130 | } 131 | } 132 | 133 | template 134 | void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon) 135 | { 136 | const double diff = actual - expected; 137 | 138 | if ( (actual != expected) && !((diff <= epsilon) && (diff >= -epsilon )) ) 139 | { 140 | std::ostringstream ss; 141 | detail::msg_prefix(ss,msg) 142 | << std::scientific 143 | << std::showpoint 144 | << std::setprecision(16) 145 | << "expected `" << expected 146 | << "` actual `" << actual 147 | << "` with precision `" << epsilon << "`"; 148 | throw failure(ss.str()); 149 | } 150 | } 151 | 152 | template 153 | void ensure_equals(const M& msg, const double& actual, const double& expected) 154 | { 155 | ensure_equals(msg, actual, expected, std::numeric_limits::epsilon()); 156 | } 157 | 158 | template 159 | void ensure_equals(const LHS& actual, const RHS& expected) 160 | { 161 | ensure_equals("Values are not equal", actual, expected); 162 | } 163 | 164 | 165 | template 166 | void ensure_equals(const std::string &msg, 167 | const LhsIterator &lhs_begin, const LhsIterator &lhs_end, 168 | const RhsIterator &rhs_begin, const RhsIterator &rhs_end) 169 | { 170 | typename std::iterator_traits::difference_type lhs_size = std::distance(lhs_begin, lhs_end); 171 | typename std::iterator_traits::difference_type rhs_size = std::distance(rhs_begin, rhs_end); 172 | 173 | if(lhs_size < rhs_size) 174 | { 175 | ensure_equals(msg + ": range is too short", lhs_size, rhs_size); 176 | } 177 | 178 | if(lhs_size > rhs_size) 179 | { 180 | ensure_equals(msg + ": range is too long", lhs_size, rhs_size); 181 | } 182 | 183 | assert(lhs_size == rhs_size); 184 | 185 | LhsIterator lhs_i = lhs_begin; 186 | RhsIterator rhs_i = rhs_begin; 187 | while( (lhs_i != lhs_end) && (rhs_i != rhs_end) ) 188 | { 189 | if(*lhs_i != *rhs_i) 190 | { 191 | std::ostringstream ss; 192 | detail::msg_prefix(ss,msg) 193 | << "expected `" << *rhs_i 194 | << "` actual `" << *lhs_i 195 | << "` at offset " << std::distance(lhs_begin, lhs_i); 196 | throw failure(ss.str()); 197 | } 198 | 199 | lhs_i++; 200 | rhs_i++; 201 | } 202 | 203 | assert(lhs_i == lhs_end); 204 | assert(rhs_i == rhs_end); 205 | } 206 | 207 | template 208 | void ensure_equals(const LhsIterator &lhs_begin, const LhsIterator &lhs_end, 209 | const RhsIterator &rhs_begin, const RhsIterator &rhs_end) 210 | { 211 | ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end); 212 | } 213 | 214 | template 215 | void ensure_equals(const LhsType *lhs_begin, const LhsType *lhs_end, 216 | const RhsType *rhs_begin, const RhsType *rhs_end) 217 | { 218 | ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end); 219 | } 220 | 221 | /** 222 | * Tests two objects for being at most in given distance one from another. 223 | * Borders are excluded. 224 | * Throws if false. 225 | * 226 | * NB: T must have operator << defined somewhere, or 227 | * client code will not compile at all! Also, T shall have 228 | * operators + and -, and be comparable. 229 | * 230 | * TODO: domains are wrong, T - T might not yield T, but Q 231 | */ 232 | template 233 | void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance) 234 | { 235 | if (expected-distance >= actual || expected+distance <= actual) 236 | { 237 | std::ostringstream ss; 238 | detail::msg_prefix(ss,msg) 239 | << " expected `" 240 | << expected-distance 241 | << "` - `" 242 | << expected+distance 243 | << "` actual `" 244 | << actual 245 | << "`"; 246 | throw failure(ss.str()); 247 | } 248 | } 249 | 250 | template 251 | void ensure_distance(const T& actual, const T& expected, const T& distance) 252 | { 253 | ensure_distance<>("Distance is wrong", actual, expected, distance); 254 | } 255 | 256 | template 257 | void ensure_errno(const M& msg, bool cond) 258 | { 259 | if(!cond) 260 | { 261 | #if defined(TUT_USE_POSIX) 262 | char e[512]; 263 | std::ostringstream ss; 264 | detail::msg_prefix(ss,msg) 265 | << strerror_r(errno, e, sizeof(e)); 266 | throw failure(ss.str()); 267 | #else 268 | throw failure(msg); 269 | #endif 270 | } 271 | } 272 | 273 | /** 274 | * Unconditionally fails with message. 275 | */ 276 | void fail(const char* msg = "") 277 | { 278 | throw failure(msg); 279 | } 280 | 281 | template 282 | void fail(const M& msg) 283 | { 284 | throw failure(msg); 285 | } 286 | 287 | /** 288 | * Mark test case as known failure and skip execution. 289 | */ 290 | void skip(const char* msg = "") 291 | { 292 | throw skipped(msg); 293 | } 294 | 295 | template 296 | void skip(const M& msg) 297 | { 298 | throw skipped(msg); 299 | } 300 | 301 | } // end of namespace 302 | 303 | } 304 | 305 | #endif 306 | 307 | -------------------------------------------------------------------------------- /tests/tut/tut_cppunit_reporter.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TUT_CPPUNIT_REPORTER 3 | #define TUT_CPPUNIT_REPORTER 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace tut 13 | { 14 | 15 | /** 16 | * CppUnit TUT reporter 17 | */ 18 | class cppunit_reporter : public tut::callback 19 | { 20 | std::vector failed_tests_; 21 | std::vector passed_tests_; 22 | const std::string filename_; 23 | std::auto_ptr stream_; 24 | 25 | 26 | cppunit_reporter(const cppunit_reporter &); 27 | cppunit_reporter &operator=(const cppunit_reporter &); 28 | 29 | public: 30 | explicit cppunit_reporter(const std::string &filename = "testResult.xml") 31 | : failed_tests_(), 32 | passed_tests_(), 33 | filename_(filename), 34 | stream_(new std::ofstream(filename_.c_str())) 35 | { 36 | if (!stream_->good()) { 37 | throw tut_error("Cannot open output file `" + filename_ + "`"); 38 | } 39 | } 40 | 41 | explicit cppunit_reporter(std::ostream &stream) 42 | : failed_tests_(), 43 | passed_tests_(), 44 | filename_(), 45 | stream_(&stream) 46 | { 47 | } 48 | 49 | ~cppunit_reporter() 50 | { 51 | if(filename_.empty()) 52 | { 53 | stream_.release(); 54 | } 55 | } 56 | 57 | void run_started() 58 | { 59 | failed_tests_.clear(); 60 | passed_tests_.clear(); 61 | } 62 | 63 | void test_completed(const tut::test_result& tr) 64 | { 65 | assert(tr.result != test_result::dummy ); 66 | if ( (tr.result == test_result::ok) || 67 | (tr.result == test_result::skipped) ) 68 | { 69 | passed_tests_.push_back(tr); 70 | } 71 | else 72 | { 73 | failed_tests_.push_back(tr); 74 | } 75 | } 76 | 77 | void run_completed() 78 | { 79 | int errors = 0; 80 | int failures = 0; 81 | std::string failure_type; 82 | std::string failure_msg; 83 | 84 | *stream_ << "" << std::endl 85 | << "" << std::endl; 86 | 87 | if (failed_tests_.size() > 0) 88 | { 89 | *stream_ << " " << std::endl; 90 | 91 | for (unsigned int i=0; i" << std::endl 134 | << " " << encode(failed_tests_[i].group) + "::" + encode(failed_tests_[i].name) << "" << std::endl 135 | << " " << failure_type << "" << std::endl 136 | << " " << std::endl 137 | << " Unknown" << std::endl 138 | << " Unknown" << std::endl 139 | << " " << std::endl 140 | << " " << encode(failure_msg + failed_tests_[i].message) << "" << std::endl 141 | << " " << std::endl; 142 | } 143 | 144 | *stream_ << " " << std::endl; 145 | } 146 | 147 | /* *********************** passed tests ***************************** */ 148 | if (passed_tests_.size() > 0) { 149 | *stream_ << " " << std::endl; 150 | 151 | for (unsigned int i=0; i" << std::endl 154 | << " " << encode(passed_tests_[i].group) + "::" + encode(passed_tests_[i].name) << "" << std::endl 155 | << " " << std::endl; 156 | } 157 | 158 | *stream_ << " " << std::endl; 159 | } 160 | 161 | /* *********************** statistics ***************************** */ 162 | *stream_ << " " << std::endl 163 | << " " << (failed_tests_.size() + passed_tests_.size()) << "" << std::endl 164 | << " " << failed_tests_.size() << "" << std::endl 165 | << " " << errors << "" << std::endl 166 | << " " << failures << "" << std::endl 167 | << " " << std::endl; 168 | 169 | /* *********************** footer ***************************** */ 170 | *stream_ << "" << std::endl; 171 | } 172 | 173 | virtual bool all_ok() const 174 | { 175 | return failed_tests_.empty(); 176 | } 177 | 178 | /** 179 | * \brief Encodes text to XML 180 | * XML-reserved characters (e.g. "<") are encoded according to specification 181 | * @param text text to be encoded 182 | * @return encoded string 183 | */ 184 | static std::string encode(const std::string & text) 185 | { 186 | std::string out; 187 | 188 | for (unsigned int i=0; i': 195 | out += ">"; 196 | break; 197 | case '&': 198 | out += "&"; 199 | break; 200 | case '\'': 201 | out += "'"; 202 | break; 203 | case '"': 204 | out += """; 205 | break; 206 | default: 207 | out += c; 208 | } 209 | } 210 | 211 | return out; 212 | } 213 | }; 214 | 215 | } 216 | 217 | #endif 218 | 219 | -------------------------------------------------------------------------------- /src/Context.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Context.h" 24 | #include "binding/Object.h" 25 | 26 | #include 27 | 28 | namespace canvas 29 | { 30 | 31 | Context::Context(int width, int height, Canvas::Format format) 32 | : m_bitmap(0), 33 | m_device(0), 34 | m_canvas(0), 35 | m_parser(), 36 | m_width(width), 37 | m_height(height), 38 | m_format(format) 39 | { 40 | m_bitmap = new SkBitmap(); 41 | m_bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); 42 | m_bitmap->allocPixels(); 43 | m_bitmap->eraseARGB(0, 0, 0, 0); 44 | 45 | m_device = new SkDevice(*m_bitmap); 46 | m_canvas = new SkCanvas(m_device); 47 | 48 | m_fillPaint.setAntiAlias(true); 49 | m_fillPaint.setStyle(SkPaint::kFill_Style); 50 | m_strokePaint.setAntiAlias(true); 51 | m_strokePaint.setStyle(SkPaint::kStroke_Style); 52 | 53 | // Initialize with default state 54 | m_stateStack.push_back(State()); 55 | syncPaintWithState(); 56 | } 57 | 58 | Context::~Context() 59 | { 60 | } 61 | 62 | void Context::copyImageTo(void * target) 63 | { 64 | void * source = m_bitmap->getPixels(); 65 | 66 | if (m_format == Canvas::kRGBA) 67 | { 68 | unsigned char * targetData = static_cast(target); 69 | unsigned char * sourceData = static_cast(source); 70 | for (size_t i = 0; i < m_bitmap->getSize(); i += 4) 71 | { 72 | targetData[i + 0] = sourceData[i + 1]; 73 | targetData[i + 1] = sourceData[i + 2]; 74 | targetData[i + 2] = sourceData[i + 3]; 75 | targetData[i + 3] = sourceData[i + 0]; 76 | } 77 | } 78 | else 79 | { 80 | memcpy(target, source, m_bitmap->getSize()); 81 | } 82 | } 83 | 84 | float Context::lineWidth() const 85 | { 86 | return currentState().lineWidth; 87 | } 88 | 89 | void Context::setLineWidth(float width) 90 | { 91 | m_strokePaint.setStrokeWidth(width); 92 | currentState().lineWidth = width; 93 | } 94 | 95 | std::string Context::lineCap() const 96 | { 97 | return currentState().lineCapString; 98 | } 99 | 100 | void Context::setLineCap(std::string const& cap) 101 | { 102 | currentState().lineCapString = cap; 103 | m_strokePaint.setStrokeCap(currentState().skiaCap()); 104 | } 105 | 106 | std::string Context::strokeStyle() const 107 | { 108 | return currentState().strokeStyleString; 109 | } 110 | 111 | void Context::setStrokeStyle(std::string const& style) 112 | { 113 | State & state = currentState(); 114 | state.strokeStyleString = style; 115 | state.strokeStyle = m_parser.parse(style); 116 | m_strokePaint.setColor(state.strokeStyle.toSkia()); 117 | } 118 | 119 | std::string Context::fillStyle() const 120 | { 121 | return currentState().fillStyleString; 122 | } 123 | 124 | void Context::setFillStyle(std::string const& style) 125 | { 126 | State & state = currentState(); 127 | state.fillStyleString = style; 128 | state.fillStyle = m_parser.parse(style); 129 | m_fillPaint.setColor(state.fillStyle.toSkia()); 130 | } 131 | 132 | float Context::globalAlpha() const 133 | { 134 | return currentState().globalAlpha; 135 | } 136 | 137 | void Context::setGlobalAlpha(float alpha) 138 | { 139 | currentState().globalAlpha = alpha; 140 | m_strokePaint.setAlpha(alpha * 255); 141 | m_fillPaint.setAlpha(alpha * 255); 142 | } 143 | 144 | void Context::scale(float x, float y) 145 | { 146 | m_canvas->scale(x, y); 147 | } 148 | 149 | void Context::rotate(float angle) 150 | { 151 | m_canvas->rotate(angle); 152 | } 153 | 154 | void Context::translate(float x, float y) 155 | { 156 | m_canvas->translate(x, y); 157 | } 158 | 159 | void Context::drawImage(ImageData * image, float x, float y, float width, float height) 160 | { 161 | m_canvas->drawBitmapRect(image->bitmap(), 0, SkRect::MakeLTRB(x, y, x + width, y + height), &m_fillPaint); 162 | } 163 | 164 | v8::Handle Context::drawImageCallback(v8::Arguments const& args) 165 | { 166 | int len = args.Length(); 167 | assert((len == 3 || len == 5) && "Wrong number or arguments to drawImage"); 168 | 169 | v8::HandleScope scope; 170 | Context * self = binding::Object::unwrap(args.Holder()); 171 | ImageData * image = binding::Object::unwrap(args[0]->ToObject()); 172 | 173 | assert(self && image); 174 | 175 | float x = binding::Translate::to(args[1]); 176 | float y = binding::Translate::to(args[2]); 177 | float width = len == 3 ? static_cast(image->width()) : binding::Translate::to(args[3]); 178 | float height = len == 3 ? static_cast(image->height()) : binding::Translate::to(args[4]); 179 | 180 | self->drawImage(image, x, y, width, height); 181 | return v8::Undefined(); 182 | } 183 | 184 | void Context::beginPath() 185 | { 186 | m_path.rewind(); 187 | } 188 | 189 | void Context::closePath() 190 | { 191 | 192 | } 193 | 194 | void Context::fill() 195 | { 196 | m_canvas->drawPath(m_path, m_fillPaint); 197 | } 198 | 199 | void Context::stroke() 200 | { 201 | m_canvas->drawPath(m_path, m_strokePaint); 202 | } 203 | 204 | void Context::clip() 205 | { 206 | 207 | } 208 | 209 | void Context::moveTo(float x, float y) 210 | { 211 | m_path.moveTo(x, y); 212 | } 213 | 214 | void Context::lineTo(float x, float y) 215 | { 216 | m_path.lineTo(x, y); 217 | } 218 | 219 | void Context::quadraticCurveTo(float cpx, float cpy, float x, float y) 220 | { 221 | m_path.quadTo(cpx, cpy, x, y); 222 | } 223 | 224 | void Context::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) 225 | { 226 | m_path.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y); 227 | } 228 | 229 | void Context::arcTo(float x1, float y1, float x2, float y2, float radius) 230 | { 231 | m_path.arcTo(x1, y1, x2, y2, radius); 232 | } 233 | 234 | void Context::rect(float x, float y, float width, float height) 235 | { 236 | m_path.addRect(x, y, x + width, y + height); 237 | } 238 | 239 | void Context::fillRect(float x, float y, float width, float height) 240 | { 241 | m_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), m_fillPaint); 242 | } 243 | 244 | void Context::strokeRect(float x, float y, float width, float height) 245 | { 246 | m_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), m_strokePaint); 247 | } 248 | 249 | void Context::clear() 250 | { 251 | m_bitmap->eraseARGB(0, 0, 0, 0); 252 | } 253 | 254 | void Context::clearRect(float x, float y, float width, float height) 255 | { 256 | SkPaint paint; 257 | paint.setColor(SkColorSetARGB(0, 0, 0,0)); 258 | m_canvas->drawRect(SkRect::MakeXYWH(x, y, width, height), paint); 259 | } 260 | 261 | void Context::syncPaintWithState() 262 | { 263 | State const& state = currentState(); 264 | 265 | m_fillPaint.setColor(state.fillStyle.toSkia()); 266 | m_fillPaint.setAlpha(state.globalAlpha * 255); 267 | 268 | m_strokePaint.setColor(state.strokeStyle.toSkia()); 269 | m_strokePaint.setAlpha(state.globalAlpha * 255); 270 | m_strokePaint.setStrokeWidth(state.lineWidth); 271 | m_strokePaint.setStrokeCap(state.skiaCap()); 272 | } 273 | } 274 | 275 | -------------------------------------------------------------------------------- /tests/tut/tut_runner.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_RUNNER_H_GUARD 2 | #define TUT_RUNNER_H_GUARD 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tut_exception.hpp" 8 | 9 | namespace tut 10 | { 11 | 12 | /** 13 | * Interface. 14 | * Test group operations. 15 | */ 16 | struct group_base 17 | { 18 | virtual ~group_base() 19 | { 20 | } 21 | 22 | // execute tests iteratively 23 | virtual void rewind() = 0; 24 | virtual bool run_next(test_result &) = 0; 25 | 26 | // execute one test 27 | virtual bool run_test(int n, test_result &tr) = 0; 28 | }; 29 | 30 | 31 | /** 32 | * Test runner callback interface. 33 | * Can be implemented by caller to update 34 | * tests results in real-time. User can implement 35 | * any of callback methods, and leave unused 36 | * in default implementation. 37 | */ 38 | struct callback 39 | { 40 | /** 41 | * Default constructor. 42 | */ 43 | callback() 44 | { 45 | } 46 | 47 | /** 48 | * Virtual destructor is a must for subclassed types. 49 | */ 50 | virtual ~callback() 51 | { 52 | } 53 | 54 | /** 55 | * Called when new test run started. 56 | */ 57 | virtual void run_started() 58 | { 59 | } 60 | 61 | /** 62 | * Called when a group started 63 | * @param name Name of the group 64 | */ 65 | virtual void group_started(const std::string& name) 66 | { 67 | (void)name; 68 | } 69 | 70 | /** 71 | * Called when a test finished. 72 | * @param tr Test results. 73 | */ 74 | virtual void test_completed(const test_result& tr) 75 | { 76 | (void)tr; 77 | } 78 | 79 | /** 80 | * Called when a group is completed 81 | * @param name Name of the group 82 | */ 83 | virtual void group_completed(const std::string& name) 84 | { 85 | (void)name; 86 | } 87 | 88 | /** 89 | * Called when all tests in run completed. 90 | */ 91 | virtual void run_completed() 92 | { 93 | } 94 | 95 | virtual bool all_ok() const 96 | { 97 | return true; 98 | } 99 | private: 100 | callback(const callback &); 101 | void operator=(const callback&); 102 | }; 103 | 104 | /** 105 | * Typedef for runner::list_groups() 106 | */ 107 | typedef std::vector groupnames; 108 | typedef std::set callbacks; 109 | 110 | /** 111 | * Test runner. 112 | */ 113 | class test_runner 114 | { 115 | 116 | public: 117 | 118 | /** 119 | * Constructor 120 | */ 121 | test_runner() 122 | : groups_(), 123 | callbacks_() 124 | { 125 | } 126 | 127 | /** 128 | * Stores another group for getting by name. 129 | * @param name new group object 130 | * @param gr new callback object 131 | */ 132 | void register_group(const std::string& name, group_base* gr) 133 | { 134 | if (gr == 0) 135 | { 136 | throw tut_error("group shall be non-null"); 137 | } 138 | 139 | if (groups_.find(name) != groups_.end()) 140 | { 141 | std::string msg("attempt to add already existent group " + name); 142 | throw tut_error(msg); 143 | } 144 | 145 | groups_.insert( std::make_pair(name, gr) ); 146 | } 147 | 148 | /** 149 | * Stores one callback object. 150 | * @param cb new callback object 151 | */ 152 | void set_callback(callback *cb) 153 | { 154 | clear_callbacks(); 155 | insert_callback(cb); 156 | } 157 | 158 | /** 159 | * Add callback object. 160 | * @param cb new callback object 161 | */ 162 | void insert_callback(callback* cb) 163 | { 164 | if(cb != NULL) 165 | { 166 | callbacks_.insert(cb); 167 | } 168 | } 169 | 170 | /** 171 | * Remove callback object. 172 | * @param cb callback to remove 173 | */ 174 | void erase_callback(callback* cb) 175 | { 176 | callbacks_.erase(cb); 177 | } 178 | 179 | /** 180 | * Remove all callback objects. 181 | */ 182 | void clear_callbacks() 183 | { 184 | callbacks_.clear(); 185 | } 186 | 187 | /** 188 | * Returns callback list. 189 | * @return callback list 190 | */ 191 | const callbacks &get_callbacks() const 192 | { 193 | return callbacks_; 194 | } 195 | 196 | /** 197 | * Set callback list. 198 | * @param cb new callback list 199 | */ 200 | void set_callbacks(const callbacks &cb) 201 | { 202 | callbacks_ = cb; 203 | } 204 | 205 | /** 206 | * Returns list of known test groups. 207 | * @return groups list 208 | */ 209 | const groupnames list_groups() const 210 | { 211 | groupnames ret; 212 | for(const_iterator i = groups_.begin(); i != groups_.end(); ++i) 213 | { 214 | ret.push_back(i->first); 215 | } 216 | return ret; 217 | } 218 | 219 | /** 220 | * Runs all tests in all groups. 221 | */ 222 | void run_tests() const 223 | { 224 | cb_run_started_(); 225 | 226 | const_iterator i = groups_.begin(); 227 | const_iterator e = groups_.end(); 228 | while (i != e) 229 | { 230 | cb_group_started_(i->first); 231 | run_all_tests_in_group_(i); 232 | cb_group_completed_(i->first); 233 | 234 | ++i; 235 | } 236 | 237 | cb_run_completed_(); 238 | } 239 | 240 | /** 241 | * Runs all tests in specified group. 242 | * @param group_name group to test 243 | */ 244 | void run_tests(const std::string& group_name) const 245 | { 246 | cb_run_started_(); 247 | 248 | const_iterator i = groups_.find(group_name); 249 | if (i == groups_.end()) 250 | { 251 | cb_run_completed_(); 252 | throw no_such_group(group_name); 253 | } 254 | 255 | cb_group_started_(group_name); 256 | run_all_tests_in_group_(i); 257 | cb_group_completed_(group_name); 258 | cb_run_completed_(); 259 | } 260 | 261 | /** 262 | * Runs one test in specified group. 263 | * @param group_name group to test 264 | * @param n run case in test 265 | * @param tr result of this case 266 | * @return true if test is ok, otherwise false 267 | */ 268 | bool run_test(const std::string& group_name, int n, test_result &tr) const 269 | { 270 | cb_run_started_(); 271 | 272 | const_iterator i = groups_.find(group_name); 273 | if (i == groups_.end()) 274 | { 275 | cb_run_completed_(); 276 | throw no_such_group(group_name); 277 | } 278 | 279 | cb_group_started_(group_name); 280 | 281 | bool t = i->second->run_test(n, tr); 282 | 283 | if(t && tr.result != test_result::dummy) 284 | { 285 | cb_test_completed_(tr); 286 | } 287 | 288 | cb_group_completed_(group_name); 289 | cb_run_completed_(); 290 | 291 | return t; 292 | } 293 | 294 | protected: 295 | 296 | typedef std::map groups; 297 | typedef groups::iterator iterator; 298 | typedef groups::const_iterator const_iterator; 299 | groups groups_; 300 | 301 | callbacks callbacks_; 302 | 303 | private: 304 | friend class restartable_wrapper; 305 | 306 | void cb_run_started_() const 307 | { 308 | for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i) 309 | { 310 | (*i)->run_started(); 311 | } 312 | } 313 | 314 | void cb_run_completed_() const 315 | { 316 | for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i) 317 | { 318 | (*i)->run_completed(); 319 | } 320 | } 321 | 322 | void cb_group_started_(const std::string &group_name) const 323 | { 324 | for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i) 325 | { 326 | (*i)->group_started(group_name); 327 | } 328 | } 329 | 330 | void cb_group_completed_(const std::string &group_name) const 331 | { 332 | for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i) 333 | { 334 | (*i)->group_completed(group_name); 335 | } 336 | } 337 | 338 | void cb_test_completed_(const test_result &tr) const 339 | { 340 | for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i) 341 | { 342 | (*i)->test_completed(tr); 343 | } 344 | } 345 | 346 | void run_all_tests_in_group_(const_iterator i) const 347 | { 348 | i->second->rewind(); 349 | 350 | test_result tr; 351 | while(i->second->run_next(tr)) 352 | { 353 | if(tr.result != test_result::dummy) 354 | { 355 | cb_test_completed_(tr); 356 | } 357 | 358 | if (tr.result == test_result::ex_ctor) 359 | { 360 | // test object ctor failed, skip whole group 361 | break; 362 | } 363 | } 364 | } 365 | }; 366 | 367 | /** 368 | * Singleton for test_runner implementation. 369 | * Instance with name runner_singleton shall be implemented 370 | * by user. 371 | */ 372 | class test_runner_singleton 373 | { 374 | public: 375 | 376 | static test_runner& get() 377 | { 378 | static test_runner tr; 379 | return tr; 380 | } 381 | }; 382 | 383 | extern test_runner_singleton runner; 384 | 385 | } 386 | 387 | #endif // TUT_RUNNER_H_GUARD 388 | 389 | -------------------------------------------------------------------------------- /src/Painter.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Daniel Wiberg 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Painter.h" 24 | #include "util/ScopedLock.h" 25 | 26 | #include 27 | 28 | namespace canvas 29 | { 30 | 31 | Painter::Painter(int width, int height, Canvas::Format format) 32 | : m_painterMutex(), 33 | m_imageMutex(), 34 | m_logMutex(), 35 | m_width(width), 36 | m_height(height), 37 | m_format(format), 38 | m_script(0), 39 | m_context(0), 40 | m_callbackIndex(0), 41 | m_windowBinding(0), 42 | m_consoleBinding(0), 43 | m_contextBinding(0), 44 | m_imageDataBinding(0) 45 | { 46 | } 47 | 48 | void Painter::start(std::string const& fileOrCode, bool isFile) 49 | { 50 | v8::HandleScope scope; 51 | 52 | // Create V8 context 53 | m_scriptTemplate = v8::Persistent::New(v8::ObjectTemplate::New()); 54 | v8::Local jsContext = v8::Local::New(v8::Context::New(0, m_scriptTemplate)); 55 | 56 | // Create bindings 57 | m_windowBinding = new binding::Object("Window"); 58 | m_windowBinding->function("setInterval", &Painter::setInterval) 59 | .function("clearInterval", &Painter::clearInterval) 60 | .function("getContext", &Painter::getContext) 61 | .function("getImage", &Painter::getImage) 62 | .attribute("width", &Painter::width, &Painter::setWidth) 63 | .attribute("height", &Painter::height, &Painter::setHeight); 64 | 65 | m_consoleBinding = new binding::Object("Console"); 66 | m_consoleBinding->function("log", &Painter::log); 67 | 68 | m_contextBinding = new binding::Object("Context"); 69 | m_contextBinding->function("scale", &Context::scale) 70 | .function("rotate", &Context::rotate) 71 | .function("translate", &Context::translate) 72 | .functionV8("drawImage", &Context::drawImageCallback) 73 | .function("beginPath", &Context::beginPath) 74 | .function("closePath", &Context::closePath) 75 | .function("moveTo", &Context::moveTo) 76 | .function("lineTo", &Context::lineTo) 77 | .function("quadraticCurveTo", &Context::quadraticCurveTo) 78 | .function("bezierCurveTo", &Context::bezierCurveTo) 79 | .function("arcTo", &Context::arcTo) 80 | .function("rect", &Context::rect) 81 | .function("fillRect", &Context::fillRect) 82 | .function("strokeRect", &Context::strokeRect) 83 | .function("fill", &Context::fill) 84 | .function("stroke", &Context::stroke) 85 | .function("clear", &Context::clear) 86 | .function("clearRéct", &Context::clearRect) 87 | .attribute("lineWidth", &Context::lineWidth, &Context::setLineWidth) 88 | .attribute("lineCap", &Context::lineCap, &Context::setLineCap) 89 | .attribute("strokeStyle", &Context::strokeStyle, &Context::setStrokeStyle) 90 | .attribute("fillStyle", &Context::fillStyle, &Context::setFillStyle) 91 | .attribute("globalAlpha", &Context::globalAlpha, &Context::setGlobalAlpha); 92 | 93 | m_imageDataBinding = new binding::Object("ImageData"); 94 | m_imageDataBinding->attribute("width", &ImageData::width, &ImageData::setWidth) 95 | .attribute("height", &ImageData::height, &ImageData::setHeight); 96 | 97 | v8::Context::Scope contextScope(jsContext); 98 | 99 | // Inject the window object 100 | jsContext->Global()->Set(v8::String::New("window"), m_windowBinding->wrap(this)); 101 | jsContext->Global()->Set(v8::String::New("console"), m_consoleBinding->wrap(this)); 102 | 103 | // Create graphics context 104 | m_context = new Context(m_width, m_height, m_format); 105 | 106 | // Create javascript object 107 | m_script = new Script(jsContext); 108 | if (isFile) 109 | m_script->load(fileOrCode); 110 | else 111 | m_script->runString(fileOrCode); 112 | 113 | m_timer.reset(); 114 | } 115 | 116 | Painter::~Painter() 117 | { 118 | delete m_script; 119 | delete m_context; 120 | delete m_imageDataBinding; 121 | delete m_contextBinding; 122 | delete m_consoleBinding; 123 | delete m_windowBinding; 124 | } 125 | 126 | void Painter::setWidth(int) 127 | { 128 | assert(0 && "Invalid operation, not allowed to set width!"); 129 | } 130 | 131 | void Painter::setHeight(int) 132 | { 133 | assert(0 && "Invalid operation, not allowed to set height!"); 134 | } 135 | 136 | void Painter::draw() 137 | { 138 | ScopedLock lock(m_painterMutex); 139 | 140 | // Call all registered callbacks 141 | v8::HandleScope scope; 142 | v8::Context::Scope contextScope(m_script->context()); 143 | v8::TryCatch tryCatch; 144 | 145 | CallbackMap::iterator it = m_callbacks.begin(); 146 | CallbackMap::iterator end = m_callbacks.end(); 147 | 148 | double dt = m_timer.seconds(); 149 | m_timer.reset(); 150 | 151 | for (; it != end; ++it) 152 | { 153 | Callback & callback = it->second; 154 | 155 | v8::Handle result = callback.call(dt); 156 | if (result.IsEmpty()) 157 | { 158 | v8::String::Utf8Value error(tryCatch.Exception()); 159 | std::cerr << "Script runtime error: " << *error << std::endl; 160 | } 161 | } 162 | } 163 | 164 | void Painter::copyImageTo(void * target) 165 | { 166 | ScopedLock lock(m_painterMutex); 167 | if (target && m_context) 168 | m_context->copyImageTo(target); 169 | } 170 | 171 | int Painter::setInterval(v8::Handle const& function, int interval) 172 | { 173 | m_callbacks.insert(std::make_pair(++m_callbackIndex, Callback(function, interval))); 174 | return m_callbackIndex; 175 | } 176 | 177 | void Painter::clearInterval(int index) 178 | { 179 | CallbackMap::iterator result = m_callbacks.find(index); 180 | if (result != m_callbacks.end()) 181 | m_callbacks.erase(result); 182 | } 183 | 184 | v8::Handle Painter::getContext(std::string const& type) 185 | { 186 | v8::HandleScope scope; 187 | if (type == "2d") 188 | return scope.Close(m_contextBinding->wrap(m_context)); 189 | 190 | std::cerr << "Error: Requested wrong context type '" << type << "'" << std::endl; 191 | return v8::Undefined(); 192 | } 193 | 194 | void Painter::registerImage(std::string const& name, ImageData * image) 195 | { 196 | assert(image); 197 | ScopedLock lock(m_imageMutex); 198 | 199 | std::map::iterator result = m_images.find(name); 200 | if (result != m_images.end()) 201 | { 202 | std::cerr << "Failed to register image '" << name << "'. Image with the same name present!" << std::endl; 203 | return; 204 | } 205 | 206 | m_images.insert(std::make_pair(name, image)); 207 | } 208 | 209 | v8::Handle Painter::getImage(std::string const& name) 210 | { 211 | ScopedLock lock(m_imageMutex); 212 | v8::HandleScope scope; 213 | 214 | std::map::iterator result = m_images.find(name); 215 | if (result == m_images.end()) 216 | return v8::Undefined(); 217 | 218 | return scope.Close(m_imageDataBinding->wrap(result->second)); 219 | } 220 | 221 | void Painter::log(std::string const& log) 222 | { 223 | ScopedLock lock(m_logMutex); 224 | 225 | m_history.push_back(log); 226 | 227 | // We only store a 1000 log entries 228 | if (m_history.size() > 1000) 229 | m_history.pop_front(); 230 | 231 | //std::cerr << log << std::endl; 232 | } 233 | 234 | std::string Painter::lastLogEntry() 235 | { 236 | ScopedLock lock(m_logMutex); 237 | 238 | if (m_history.empty()) 239 | return ""; 240 | 241 | std::string log = m_history.front(); 242 | m_history.pop_front(); 243 | return log; 244 | } 245 | 246 | } 247 | 248 | -------------------------------------------------------------------------------- /tests/tut/tut_restartable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_RESTARTABLE_H_GUARD 2 | #define TUT_RESTARTABLE_H_GUARD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /** 11 | * Optional restartable wrapper for test_runner. 12 | * 13 | * Allows to restart test runs finished due to abnormal 14 | * test application termination (such as segmentation 15 | * fault or math error). 16 | * 17 | * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com 18 | */ 19 | 20 | namespace tut 21 | { 22 | 23 | namespace util 24 | { 25 | 26 | /** 27 | * Escapes non-alphabetical characters in string. 28 | */ 29 | std::string escape(const std::string& orig) 30 | { 31 | std::string rc; 32 | std::string::const_iterator i,e; 33 | i = orig.begin(); 34 | e = orig.end(); 35 | 36 | while (i != e) 37 | { 38 | if ((*i >= 'a' && *i <= 'z') || 39 | (*i >= 'A' && *i <= 'Z') || 40 | (*i >= '0' && *i <= '9') ) 41 | { 42 | rc += *i; 43 | } 44 | else 45 | { 46 | rc += '\\'; 47 | rc += ('a'+(((unsigned int)*i) >> 4)); 48 | rc += ('a'+(((unsigned int)*i) & 0xF)); 49 | } 50 | 51 | ++i; 52 | } 53 | return rc; 54 | } 55 | 56 | /** 57 | * Un-escapes string. 58 | */ 59 | std::string unescape(const std::string& orig) 60 | { 61 | std::string rc; 62 | std::string::const_iterator i,e; 63 | i = orig.begin(); 64 | e = orig.end(); 65 | 66 | while (i != e) 67 | { 68 | if (*i != '\\') 69 | { 70 | rc += *i; 71 | } 72 | else 73 | { 74 | ++i; 75 | if (i == e) 76 | { 77 | throw std::invalid_argument("unexpected end of string"); 78 | } 79 | unsigned int c1 = *i; 80 | ++i; 81 | if (i == e) 82 | { 83 | throw std::invalid_argument("unexpected end of string"); 84 | } 85 | unsigned int c2 = *i; 86 | rc += (((c1 - 'a') << 4) + (c2 - 'a')); 87 | } 88 | 89 | ++i; 90 | } 91 | return rc; 92 | } 93 | 94 | /** 95 | * Serialize test_result avoiding interfering with operator <<. 96 | */ 97 | void serialize(std::ostream& os, const tut::test_result& tr) 98 | { 99 | os << escape(tr.group) << std::endl; 100 | os << tr.test << ' '; 101 | switch(tr.result) 102 | { 103 | case test_result::ok: 104 | os << 0; 105 | break; 106 | case test_result::fail: 107 | os << 1; 108 | break; 109 | case test_result::ex: 110 | os << 2; 111 | break; 112 | case test_result::warn: 113 | os << 3; 114 | break; 115 | case test_result::term: 116 | os << 4; 117 | break; 118 | case test_result::rethrown: 119 | os << 5; 120 | break; 121 | case test_result::ex_ctor: 122 | os << 6; 123 | break; 124 | case test_result::dummy: 125 | assert(!"Should never be called"); 126 | default: 127 | throw std::logic_error("operator << : bad result_type"); 128 | } 129 | os << ' ' << escape(tr.message) << std::endl; 130 | } 131 | 132 | /** 133 | * deserialization for test_result 134 | */ 135 | bool deserialize(std::istream& is, tut::test_result& tr) 136 | { 137 | std::getline(is,tr.group); 138 | if (is.eof()) 139 | { 140 | return false; 141 | } 142 | tr.group = unescape(tr.group); 143 | 144 | tr.test = -1; 145 | is >> tr.test; 146 | if (tr.test < 0) 147 | { 148 | throw std::logic_error("operator >> : bad test number"); 149 | } 150 | 151 | int n = -1; 152 | is >> n; 153 | switch(n) 154 | { 155 | case 0: 156 | tr.result = test_result::ok; 157 | break; 158 | case 1: 159 | tr.result = test_result::fail; 160 | break; 161 | case 2: 162 | tr.result = test_result::ex; 163 | break; 164 | case 3: 165 | tr.result = test_result::warn; 166 | break; 167 | case 4: 168 | tr.result = test_result::term; 169 | break; 170 | case 5: 171 | tr.result = test_result::rethrown; 172 | break; 173 | case 6: 174 | tr.result = test_result::ex_ctor; 175 | break; 176 | default: 177 | throw std::logic_error("operator >> : bad result_type"); 178 | } 179 | 180 | is.ignore(1); // space 181 | std::getline(is,tr.message); 182 | tr.message = unescape(tr.message); 183 | if (!is.good()) 184 | { 185 | throw std::logic_error("malformed test result"); 186 | } 187 | return true; 188 | } 189 | } 190 | 191 | /** 192 | * Restartable test runner wrapper. 193 | */ 194 | class restartable_wrapper 195 | { 196 | test_runner& runner_; 197 | callbacks callbacks_; 198 | 199 | std::string dir_; 200 | std::string log_; // log file: last test being executed 201 | std::string jrn_; // journal file: results of all executed tests 202 | 203 | public: 204 | /** 205 | * Default constructor. 206 | * @param dir Directory where to search/put log and journal files 207 | */ 208 | restartable_wrapper(const std::string& dir = ".") 209 | : runner_(runner.get()), 210 | callbacks_(), 211 | dir_(dir), 212 | log_( dir + '/' + "log.tut" ), 213 | jrn_( dir + '/' + "journal.tut" ) 214 | { 215 | // dozen: it works, but it would be better to use system path separator 216 | } 217 | 218 | /** 219 | * Stores another group for getting by name. 220 | */ 221 | void register_group(const std::string& name, group_base* gr) 222 | { 223 | runner_.register_group(name,gr); 224 | } 225 | 226 | /** 227 | * Stores callback object. 228 | */ 229 | void set_callback(callback* cb) 230 | { 231 | callbacks_.clear(); 232 | callbacks_.insert(cb); 233 | } 234 | 235 | void insert_callback(callback* cb) 236 | { 237 | callbacks_.insert(cb); 238 | } 239 | 240 | void erase_callback(callback* cb) 241 | { 242 | callbacks_.erase(cb); 243 | } 244 | 245 | void set_callbacks(const callbacks& cb) 246 | { 247 | callbacks_ = cb; 248 | } 249 | 250 | const callbacks& get_callbacks() const 251 | { 252 | return runner_.get_callbacks(); 253 | } 254 | 255 | /** 256 | * Returns list of known test groups. 257 | */ 258 | groupnames list_groups() const 259 | { 260 | return runner_.list_groups(); 261 | } 262 | 263 | /** 264 | * Runs all tests in all groups. 265 | */ 266 | void run_tests() const 267 | { 268 | // where last run was failed 269 | std::string fail_group; 270 | int fail_test; 271 | read_log_(fail_group,fail_test); 272 | bool fail_group_reached = (fail_group == ""); 273 | 274 | // iterate over groups 275 | tut::groupnames gn = list_groups(); 276 | tut::groupnames::const_iterator gni,gne; 277 | gni = gn.begin(); 278 | gne = gn.end(); 279 | while (gni != gne) 280 | { 281 | // skip all groups before one that failed 282 | if (!fail_group_reached) 283 | { 284 | if (*gni != fail_group) 285 | { 286 | ++gni; 287 | continue; 288 | } 289 | fail_group_reached = true; 290 | } 291 | 292 | // first or restarted run 293 | int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1; 294 | while(true) 295 | { 296 | // last executed test pos 297 | register_execution_(*gni,test); 298 | 299 | tut::test_result tr; 300 | if( !runner_.run_test(*gni,test, tr) || tr.result == test_result::dummy ) 301 | { 302 | break; 303 | } 304 | register_test_(tr); 305 | 306 | ++test; 307 | } 308 | 309 | ++gni; 310 | } 311 | 312 | // show final results to user 313 | invoke_callback_(); 314 | 315 | // truncate files as mark of successful finish 316 | truncate_(); 317 | } 318 | 319 | private: 320 | /** 321 | * Shows results from journal file. 322 | */ 323 | void invoke_callback_() const 324 | { 325 | runner_.set_callbacks(callbacks_); 326 | runner_.cb_run_started_(); 327 | 328 | std::string current_group; 329 | std::ifstream ijournal(jrn_.c_str()); 330 | while (ijournal.good()) 331 | { 332 | tut::test_result tr; 333 | if( !util::deserialize(ijournal,tr) ) 334 | { 335 | break; 336 | } 337 | runner_.cb_test_completed_(tr); 338 | } 339 | 340 | runner_.cb_run_completed_(); 341 | } 342 | 343 | /** 344 | * Register test into journal. 345 | */ 346 | void register_test_(const test_result& tr) const 347 | { 348 | std::ofstream ojournal(jrn_.c_str(), std::ios::app); 349 | util::serialize(ojournal, tr); 350 | ojournal << std::flush; 351 | if (!ojournal.good()) 352 | { 353 | throw std::runtime_error("unable to register test result in file " 354 | + jrn_); 355 | } 356 | } 357 | 358 | /** 359 | * Mark the fact test going to be executed 360 | */ 361 | void register_execution_(const std::string& grp, int test) const 362 | { 363 | // last executed test pos 364 | std::ofstream olog(log_.c_str()); 365 | olog << util::escape(grp) << std::endl << test << std::endl << std::flush; 366 | if (!olog.good()) 367 | { 368 | throw std::runtime_error("unable to register execution in file " 369 | + log_); 370 | } 371 | } 372 | 373 | /** 374 | * Truncate tests. 375 | */ 376 | void truncate_() const 377 | { 378 | std::ofstream olog(log_.c_str()); 379 | std::ofstream ojournal(jrn_.c_str()); 380 | } 381 | 382 | /** 383 | * Read log file 384 | */ 385 | void read_log_(std::string& fail_group, int& fail_test) const 386 | { 387 | // read failure point, if any 388 | std::ifstream ilog(log_.c_str()); 389 | std::getline(ilog,fail_group); 390 | fail_group = util::unescape(fail_group); 391 | ilog >> fail_test; 392 | if (!ilog.good()) 393 | { 394 | fail_group = ""; 395 | fail_test = -1; 396 | truncate_(); 397 | } 398 | else 399 | { 400 | // test was terminated... 401 | tut::test_result tr(fail_group, fail_test, "", tut::test_result::term); 402 | register_test_(tr); 403 | } 404 | } 405 | }; 406 | 407 | } 408 | 409 | #endif 410 | 411 | -------------------------------------------------------------------------------- /tests/tut/tut_xml_reporter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TUT_XML_REPORTER 2 | #define TUT_XML_REPORTER 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace tut 13 | { 14 | 15 | /** 16 | * \brief JUnit XML TUT reporter 17 | * @author Lukasz Maszczynski, NSN 18 | * @date 11/07/2008 19 | */ 20 | class xml_reporter : public tut::callback 21 | { 22 | typedef std::vector TestResults; 23 | typedef std::map TestGroups; 24 | 25 | TestGroups all_tests_; /// holds all test results 26 | const std::string filename_; /// filename base 27 | std::auto_ptr stream_; 28 | 29 | /** 30 | * \brief Builds "testcase" XML entity with given parameters 31 | * Builds \ entity according to given parameters. \-s are part of \. 32 | * @param tr test result to be used as source data 33 | * @param failure_type type of failure to be reported ("Assertion" or "Error", empty if test passed) 34 | * @param failure_msg failure message to be reported (empty, if test passed) 35 | * @return string with \ entity 36 | */ 37 | std::string xml_build_testcase(const tut::test_result & tr, const std::string & failure_type, 38 | const std::string & failure_msg, int pid = 0) 39 | { 40 | using std::endl; 41 | using std::string; 42 | 43 | std::ostringstream out; 44 | 45 | if ( (tr.result == test_result::ok) || 46 | (tr.result == test_result::skipped) ) 47 | { 48 | out << " "; 49 | } 50 | else 51 | { 52 | string err_msg = cppunit_reporter::encode(failure_msg + tr.message); 53 | 54 | string tag; // determines tag name: "failure" or "error" 55 | if ( tr.result == test_result::fail || tr.result == test_result::warn || 56 | tr.result == test_result::ex || tr.result == test_result::ex_ctor || tr.result == test_result::rethrown ) 57 | { 58 | tag = "failure"; 59 | } 60 | else 61 | { 62 | tag = "error"; 63 | } 64 | 65 | out << " " << endl; 66 | out << " <" << tag << " message=\"" << err_msg << "\"" << " type=\"" << failure_type << "\""; 67 | #if defined(TUT_USE_POSIX) 68 | if(pid != getpid()) 69 | { 70 | out << " child=\"" << pid << "\""; 71 | } 72 | #else 73 | (void)pid; 74 | #endif 75 | out << ">" << err_msg << "" << endl; 76 | out << " "; 77 | } 78 | 79 | return out.str(); 80 | } 81 | 82 | /** 83 | * \brief Builds "testsuite" XML entity 84 | * Builds \ XML entity according to given parameters. 85 | * @param errors number of errors to be reported 86 | * @param failures number of failures to be reported 87 | * @param total total number of tests to be reported 88 | * @param name test suite name 89 | * @param testcases cppunit_reporter::encoded XML string containing testcases 90 | * @return string with \ entity 91 | */ 92 | std::string xml_build_testsuite(int errors, int failures, int total, 93 | const std::string & name, const std::string & testcases) 94 | { 95 | std::ostringstream out; 96 | 97 | out << " " << std::endl; 98 | out << testcases; 99 | out << " "; 100 | 101 | return out.str(); 102 | } 103 | 104 | public: 105 | int ok_count; /// number of passed tests 106 | int exceptions_count; /// number of tests that threw exceptions 107 | int failures_count; /// number of tests that failed 108 | int terminations_count; /// number of tests that would terminate 109 | int warnings_count; /// number of tests where destructors threw an exception 110 | 111 | /** 112 | * \brief Default constructor 113 | * @param filename base filename 114 | */ 115 | xml_reporter(const std::string & filename) 116 | : all_tests_(), 117 | filename_(filename), 118 | stream_(new std::ofstream(filename_.c_str())), 119 | ok_count(0), 120 | exceptions_count(0), 121 | failures_count(0), 122 | terminations_count(0), 123 | warnings_count(0) 124 | { 125 | if (!stream_->good()) { 126 | throw tut_error("Cannot open output file `" + filename_ + "`"); 127 | } 128 | } 129 | 130 | xml_reporter(std::ostream & stream) 131 | : all_tests_(), 132 | filename_(), 133 | stream_(&stream), 134 | ok_count(0), 135 | exceptions_count(0), 136 | failures_count(0), 137 | terminations_count(0), 138 | warnings_count(0) 139 | { 140 | } 141 | 142 | ~xml_reporter() 143 | { 144 | if(filename_.empty()) 145 | { 146 | stream_.release(); 147 | } 148 | } 149 | 150 | /** 151 | * \brief Callback function 152 | * This function is called before the first test is executed. It initializes counters. 153 | */ 154 | virtual void run_started() 155 | { 156 | ok_count = 0; 157 | exceptions_count = 0; 158 | failures_count = 0; 159 | terminations_count = 0; 160 | warnings_count = 0; 161 | all_tests_.clear(); 162 | } 163 | 164 | /** 165 | * \brief Callback function 166 | * This function is called when test completes. Counters are updated here, and test results stored. 167 | */ 168 | virtual void test_completed(const tut::test_result& tr) 169 | { 170 | // update global statistics 171 | switch (tr.result) { 172 | case test_result::ok: 173 | case test_result::skipped: 174 | ok_count++; 175 | break; 176 | case test_result::fail: 177 | case test_result::rethrown: 178 | failures_count++; 179 | break; 180 | case test_result::ex: 181 | case test_result::ex_ctor: 182 | exceptions_count++; 183 | break; 184 | case test_result::warn: 185 | warnings_count++; 186 | break; 187 | case test_result::term: 188 | terminations_count++; 189 | break; 190 | case tut::test_result::dummy: 191 | assert(!"Should never be called"); 192 | } // switch 193 | 194 | // add test result to results table 195 | all_tests_[tr.group].push_back(tr); 196 | } 197 | 198 | /** 199 | * \brief Callback function 200 | * This function is called when all tests are completed. It generates XML output 201 | * to file(s). File name base can be set with constructor. 202 | */ 203 | virtual void run_completed() 204 | { 205 | /* *********************** header ***************************** */ 206 | *stream_ << "" << std::endl; 207 | *stream_ << "" << std::endl; 208 | 209 | // iterate over all test groups 210 | for (TestGroups::const_iterator tgi = all_tests_.begin(); tgi != all_tests_.end(); ++tgi) 211 | { 212 | /* per-group statistics */ 213 | int passed = 0; // passed in single group 214 | int exceptions = 0; // exceptions in single group 215 | int failures = 0; // failures in single group 216 | int terminations = 0; // terminations in single group 217 | int warnings = 0; // warnings in single group 218 | int errors = 0; // errors in single group 219 | 220 | 221 | // output is written to string stream buffer, because JUnit format tag 222 | // contains statistics, which aren't known yet 223 | std::ostringstream out; 224 | 225 | // iterate over all test cases in the current test group 226 | const TestResults &results = tgi->second; 227 | for (TestResults::const_iterator tri = results.begin(); tri != results.end(); ++tri) 228 | { 229 | std::string failure_type; // string describing the failure type 230 | std::string failure_msg; // a string with failure message 231 | 232 | switch (tri->result) 233 | { 234 | case test_result::ok: 235 | case test_result::skipped: 236 | passed++; 237 | break; 238 | case test_result::fail: 239 | failure_type = "Assertion"; 240 | failure_msg = ""; 241 | failures++; 242 | break; 243 | case test_result::ex: 244 | failure_type = "Assertion"; 245 | failure_msg = "Thrown exception: " + tri->exception_typeid + '\n'; 246 | exceptions++; 247 | break; 248 | case test_result::warn: 249 | failure_type = "Assertion"; 250 | failure_msg = "Destructor failed.\n"; 251 | warnings++; 252 | break; 253 | case test_result::term: 254 | failure_type = "Error"; 255 | failure_msg = "Test application terminated abnormally.\n"; 256 | terminations++; 257 | break; 258 | case test_result::ex_ctor: 259 | failure_type = "Assertion"; 260 | failure_msg = "Constructor has thrown an exception: " + tri->exception_typeid + ".\n"; 261 | exceptions++; 262 | break; 263 | case test_result::rethrown: 264 | failure_type = "Assertion"; 265 | failure_msg = "Child failed.\n"; 266 | failures++; 267 | break; 268 | default: 269 | failure_type = "Error"; 270 | failure_msg = "Unknown test status, this should have never happened. " 271 | "You may just have found a bug in TUT, please report it immediately.\n"; 272 | errors++; 273 | break; 274 | } // switch 275 | 276 | #if defined(TUT_USE_POSIX) 277 | out << xml_build_testcase(*tri, failure_type, failure_msg, tri->pid) << std::endl; 278 | #else 279 | out << xml_build_testcase(*tri, failure_type, failure_msg) << std::endl; 280 | #endif 281 | } // iterate over all test cases 282 | 283 | // calculate per-group statistics 284 | int stat_errors = terminations + errors; 285 | int stat_failures = failures + warnings + exceptions; 286 | int stat_all = stat_errors + stat_failures + passed; 287 | 288 | *stream_ << xml_build_testsuite(stat_errors, stat_failures, stat_all, (*tgi).first/* name */, out.str()/* testcases */) << std::endl; 289 | } // iterate over all test groups 290 | 291 | *stream_ << "" << std::endl; 292 | } 293 | 294 | /** 295 | * \brief Returns true, if all tests passed 296 | */ 297 | virtual bool all_ok() const 298 | { 299 | return ( (terminations_count + failures_count + warnings_count + exceptions_count) == 0); 300 | }; 301 | }; 302 | 303 | } 304 | 305 | #endif 306 | --------------------------------------------------------------------------------