diff --git a/.gitmodules b/.gitmodules index bcb194467..b9d8b9625 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,7 +12,7 @@ url = https://github.com/aseprite/duktape.git [submodule "third_party/libwebp"] path = third_party/libwebp - url = https://chromium.googlesource.com/webm/libwebp + url = https://github.com/aseprite/libwebp.git [submodule "src/flic"] path = src/flic url = https://github.com/aseprite/flic.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ed77f00af..2f3978335 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,12 @@ if(WITH_WEBP_SUPPORT) message(FATAL_ERROR "libwebp not found") endif() else() - set(WEBP_LIBRARIES webp) + # Skia already includes webp library + if(NOT USE_SKIA_BACKEND) + set(WEBP_LIBRARIES webp) + else() + set(WEBP_LIBRARIES "") + endif() set(WEBP_INCLUDE_DIR ${LIBWEBP_DIR}/src) endif() include_directories(${WEBP_INCLUDE_DIR}) diff --git a/INSTALL.md b/INSTALL.md index 31d402ef2..f2727a794 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -4,18 +4,18 @@ * [Get the source code](#get-the-source-code) * [Dependencies](#dependencies) * [Windows dependencies](#windows-dependencies) - * [Mac OS X dependencies](#mac-os-x-dependencies) + * [macOS dependencies](#macos-dependencies) * [Linux dependencies](#linux-dependencies) * [Compiling](#compiling) * [Windows details](#windows-details) - * [Mac OS X details](#mac-os-x-details) + * [macOS details](#macos-details) * [Issues with Retina displays](#issues-with-retina-displays) * [Linux details](#linux-details) * [Using shared third party libraries](#using-shared-third-party-libraries) * [Linux issues](#linux-issues) * [Building Skia dependency](#building-skia-dependency) * [Skia on Windows](#skia-on-windows) - * [Skia on Mac OS X](#skia-on-mac-os-x) + * [Skia on macOS](#skia-on-macos) # Platforms @@ -23,7 +23,7 @@ You should be able to compile Aseprite successfully on the following platforms: * Windows 10 + VS2015 Community Edition + Windows 10 SDK -* Mac OS X 10.11.4 El Capitan + Xcode 7.3 + OS X 10.11 SDK + Skia (without GPU) +* macOS 10.12.1 Sierra + Xcode 8.0 + macOS 10.12 SDK + Skia * Linux + gcc 4.8 with some C++11 support # Get the source code @@ -62,7 +62,7 @@ Aseprite can be compiled with two different back-ends: removed in future versions. All new development is being done in the new Skia back-end. -2. Skia back-end (Windows, Mac OS X): You will need a compiled version +2. Skia back-end (Windows, macOS): You will need a compiled version of the Skia library. Please check the details about [how to build Skia](#building-skia-dependency) on your platform. @@ -83,12 +83,12 @@ After that you have to choose the back-end: [Windows details](#windows-details) section to know how to call `cmake` correctly. -## Mac OS X dependencies +## macOS dependencies -On OS X you will need Mac OS X 10.11 SDK and Xcode 7.3 (maybe older -versions might work). +On macOS you will need macOS 10.12 SDK and Xcode 8.0 (older versions +might work). -Also, you must compile [Skia](#skia-on-mac-os-x) before starting with +Also, you must compile [Skia](#skia-on-macos) before starting with the [compilation](#compiling). ## Linux dependencies @@ -121,7 +121,7 @@ The `libxcursor-dev` package is needed to Here `cmake` needs different options depending on your platform. You must check the details for - [Windows](#windows-details), [OS X](#mac-os-x-details), and + [Windows](#windows-details), [macOS](#macos-details), and [Linux](#linux-details). Some `cmake` options can be modified using tools like [`ccmake`](https://cmake.org/cmake/help/latest/manual/ccmake.1.html) or [`cmake-gui`](https://cmake.org/cmake/help/latest/manual/cmake-gui.1.html). @@ -150,9 +150,9 @@ with the following arguments: In this case, `C:\deps\skia` is the directory where Skia was compiled as described in [Skia on Windows](#skia-on-windows) section. -## Mac OS X details +## macOS details -After [compiling Skia](#skia-on-mac-os-x), you should run `cmake` with +After [compiling Skia](#skia-on-macos), you should run `cmake` with the following parameters and then `ninja`: cd aseprite @@ -161,7 +161,7 @@ the following parameters and then `ninja`: cmake \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \ - -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \ + -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk \ -DUSE_ALLEG4_BACKEND=OFF \ -DUSE_SKIA_BACKEND=ON \ -DSKIA_DIR=$HOME/deps/skia \ @@ -171,7 +171,7 @@ the following parameters and then `ninja`: ninja aseprite In this case, `$HOME/deps/skia` is the directory where Skia was -compiled as described in [Skia on Mac OS X](#skia-on-mac-os-x) section. +compiled as described in [Skia on macOS](#skia-on-macos) section. ### Issues with Retina displays @@ -220,13 +220,13 @@ known issues solved in # Building Skia dependency When you compile Aseprite with [Skia](https://skia.org) as back-end on -Windows or OS X, you need to compile a specific version of Skia. In +Windows or macOS, you need to compile a specific version of Skia. In the following sections you will find straightforward steps to compile Skia. You can always check the [official Skia instructions](https://skia.org/user/quick) and select -the OS you are building for. Aseprite uses the `aseprite-m53` Skia +the OS you are building for. Aseprite uses the `aseprite-m55` Skia branch from `https://github.com/aseprite/skia`. ## Skia on Windows @@ -249,7 +249,7 @@ Just ignore it.) cd C:\deps git clone https://github.com/aseprite/skia.git cd skia - git checkout aseprite-m53 + git checkout aseprite-m55 python bin/sync-and-gyp (The `bin/sync-and-gyp` will take some minutes because it downloads a @@ -260,7 +260,7 @@ lot of packages, please wait and re-run the same command in case it fails.) More information about these steps in the [official Skia documentation](https://skia.org/user/quick/windows). -## Skia on Mac OS X +## Skia on macOS These steps will create a `deps` folder in your home directory with a couple of subdirectories needed to build Skia (you can change the @@ -273,14 +273,14 @@ several minutes to finish: git clone https://github.com/aseprite/skia.git export PATH="${PWD}/depot_tools:${PATH}" cd skia - git checkout aseprite-m53 + git checkout aseprite-m55 python bin/sync-and-gyp ninja -C out/Release dm After this you should have all Skia libraries compiled. When you [compile Aseprite](#compiling), remember to add `-DSKIA_DIR=$HOME/deps/skia` parameter to your `cmake` call as -described in the [Mac OS X details](#mac-os-x-details) section. +described in the [macOS details](#macos-details) section. More information about these steps in the [official Skia documentation](https://skia.org/user/quick/macos). diff --git a/data/palettes/master-system.gpl b/data/palettes/master-system.gpl index 256867e1d..b6494b7d1 100644 --- a/data/palettes/master-system.gpl +++ b/data/palettes/master-system.gpl @@ -1,34 +1,67 @@ GIMP Palette +Columns: 16 # - 85 0 85 Untitled -170 85 170 Untitled -255 170 255 Untitled - 0 0 85 Untitled - 85 85 170 Untitled -170 170 255 Untitled - 85 170 170 Untitled - 0 85 85 Untitled -170 255 255 Untitled - 0 85 0 Untitled -170 255 170 Untitled - 85 170 0 Untitled -170 255 0 Untitled -170 170 0 Untitled - 85 85 0 Untitled -255 255 85 Untitled -170 170 85 Untitled -255 255 170 Untitled -255 170 0 Untitled -170 85 0 Untitled -255 170 85 Untitled -255 85 0 Untitled -255 0 0 Untitled -170 0 0 Untitled - 85 0 0 Untitled -255 85 85 Untitled -170 85 85 Untitled -255 170 170 Untitled -255 255 255 Untitled -170 170 170 Untitled - 85 85 85 Untitled - 0 0 0 Untitled + 0 0 0 Untitled + 85 0 0 Untitled +170 0 0 Untitled +255 0 0 Untitled + 0 85 0 Untitled + 85 85 0 Untitled +170 85 0 Untitled +255 85 0 Untitled + 0 170 0 Untitled + 85 170 0 Untitled +170 170 0 Untitled +255 170 0 Untitled + 0 255 0 Untitled + 85 255 0 Untitled +170 255 0 Untitled +255 255 0 Untitled + 0 0 85 Untitled + 85 0 85 Untitled +170 0 85 Untitled +255 0 85 Untitled + 0 85 85 Untitled + 85 85 85 Untitled +170 85 85 Untitled +255 85 85 Untitled + 0 170 85 Untitled + 85 170 85 Untitled +170 170 85 Untitled +255 170 85 Untitled + 0 255 85 Untitled + 85 255 85 Untitled +170 255 85 Untitled +255 255 85 Untitled + 0 0 170 Untitled + 85 0 170 Untitled +170 0 170 Untitled +255 0 170 Untitled + 0 85 170 Untitled + 85 85 170 Untitled +170 85 170 Untitled +255 85 170 Untitled + 0 170 170 Untitled + 85 170 170 Untitled +170 170 170 Untitled +255 170 170 Untitled + 0 255 170 Untitled + 85 255 170 Untitled +170 255 170 Untitled +255 255 170 Untitled + 0 0 255 Untitled + 85 0 255 Untitled +170 0 255 Untitled +255 0 255 Untitled + 0 85 255 Untitled + 85 85 255 Untitled +170 85 255 Untitled +255 85 255 Untitled + 0 170 255 Untitled + 85 170 255 Untitled +170 170 255 Untitled +255 170 255 Untitled + 0 255 255 Untitled + 85 255 255 Untitled +170 255 255 Untitled +255 255 255 Untitled diff --git a/data/pref.xml b/data/pref.xml index 2229acd4f..b27cefb9a 100644 --- a/data/pref.xml +++ b/data/pref.xml @@ -60,7 +60,7 @@ -! + diff --git a/data/skins/default/skin.xml b/data/skins/default/skin.xml index 290f0cb40..e1c672ea6 100644 --- a/data/skins/default/skin.xml +++ b/data/skins/default/skin.xml @@ -18,6 +18,7 @@ + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 437dcca07..83403c73a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,7 @@ add_subdirectory(gen) add_subdirectory(gfx) add_subdirectory(net) add_subdirectory(render) +add_subdirectory(docio) add_subdirectory(script) add_subdirectory(she) add_subdirectory(ui) diff --git a/src/README.md b/src/README.md index c67c5b937..99986a5e5 100644 --- a/src/README.md +++ b/src/README.md @@ -47,11 +47,11 @@ because they don't depend on any other component. ## Level 4 - * [iff](iff/) (base, doc, render): Image File Formats library (load/save documents). + * [docio](docio/) (base, flic): Load/save documents. ## Level 5 - * [app](app/) (allegro, base, doc, filters, fixmath, gfx, iff, pen, render, scripting, she, ui, undo, updater, webserver) + * [app](app/) (allegro, base, doc, docio, filters, fixmath, flic, gfx, pen, render, scripting, she, ui, undo, updater, webserver) ## Level 6 diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 1ca0ea29f..340ae7d27 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -461,6 +461,7 @@ target_link_libraries(app-lib clip css-lib doc-lib + docio-lib filters-lib fixmath-lib flic-lib diff --git a/src/app/app.cpp b/src/app/app.cpp index 337d1f4e4..c5a5c460d 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -166,7 +166,7 @@ void App::initialize(const AppOptions& options) m_modules->createDataRecovery(); if (isPortable()) - LOG("Running in portable mode\n"); + LOG("APP: Running in portable mode\n"); // Load or create the default palette, or migrate the default // palette from an old format palette to the new one, etc. @@ -174,7 +174,7 @@ void App::initialize(const AppOptions& options) // Initialize GUI interface if (isGui()) { - LOG("GUI mode\n"); + LOG("APP: GUI mode\n"); // Setup the GUI cursor and redraw screen @@ -202,7 +202,7 @@ void App::initialize(const AppOptions& options) } // Procress options - LOG("Processing options...\n"); + LOG("APP: Processing options...\n"); { base::UniquePtr delegate; if (options.previewCLI()) @@ -297,11 +297,9 @@ void App::run() App::~App() { try { + LOG("APP: Exit\n"); ASSERT(m_instance == this); - // Remove Aseprite handlers - LOG("ASE: Uninstalling\n"); - // Delete file formats. FileFormatsManager::destroyInstance(); @@ -325,12 +323,13 @@ App::~App() m_instance = NULL; } catch (const std::exception& e) { + LOG(ERROR) << "APP: Error: " << e.what() << "\n"; she::error_message(e.what()); // no re-throw } catch (...) { - she::error_message("Error closing ASE.\n(uncaught exception)"); + she::error_message("Error closing " PACKAGE ".\n(uncaught exception)"); // no re-throw } diff --git a/src/app/app_brushes.cpp b/src/app/app_brushes.cpp index ce0e6b057..bf2c92a00 100644 --- a/src/app/app_brushes.cpp +++ b/src/app/app_brushes.cpp @@ -185,7 +185,7 @@ AppBrushes::AppBrushes() load(fn); } catch (const std::exception& ex) { - LOG("Error loading user brushes: %s", ex.what()); + LOG(ERROR) << "BRSH: Error loading user brushes: " << ex.what() << "\n"; } } diff --git a/src/app/app_menus.cpp b/src/app/app_menus.cpp index a8cb34f4d..ac441ca6d 100644 --- a/src/app/app_menus.cpp +++ b/src/app/app_menus.cpp @@ -71,7 +71,7 @@ void AppMenus::reload() //////////////////////////////////////// // Load menus - LOG(" - Loading menus from \"%s\"...\n", path); + LOG("MENU: Loading menus from %s\n", path); m_rootMenu.reset(loadMenuById(handle, "main_menu")); @@ -81,7 +81,7 @@ void AppMenus::reload() m_rootMenu->insertChild(0, createInvalidVersionMenuitem()); #endif - LOG("Main menu loaded.\n"); + LOG("MENU: Main menu loaded.\n"); m_tabPopupMenu.reset(loadMenuById(handle, "tab_popup")); m_documentTabPopupMenu.reset(loadMenuById(handle, "document_tab_popup")); @@ -96,7 +96,7 @@ void AppMenus::reload() //////////////////////////////////////// // Load keyboard shortcuts for commands - LOG(" - Loading commands keyboard shortcuts from \"%s\"...\n", path); + LOG("MENU: Loading commands keyboard shortcuts from %s\n", path); TiXmlElement* xmlKey = handle .FirstChild("gui") @@ -167,8 +167,6 @@ Menu* AppMenus::loadMenuById(TiXmlHandle& handle, const char* id) { ASSERT(id != NULL); - //LOG("loadMenuById(%s)\n", id); - // TiXmlElement* xmlMenu = handle .FirstChild("gui") @@ -190,8 +188,6 @@ Menu* AppMenus::convertXmlelemToMenu(TiXmlElement* elem) { Menu* menu = new Menu(); - //LOG("convertXmlelemToMenu(%s, %s, %s)\n", elem->Value(), elem->Attribute("id"), elem->Attribute("text")); - TiXmlElement* child = elem->FirstChildElement(); while (child) { Widget* menuitem = convertXmlelemToMenuitem(child); diff --git a/src/app/cli/default_cli_delegate.cpp b/src/app/cli/default_cli_delegate.cpp index fdef561a6..f8f139498 100644 --- a/src/app/cli/default_cli_delegate.cpp +++ b/src/app/cli/default_cli_delegate.cpp @@ -103,13 +103,13 @@ void DefaultCliDelegate::loadPalette(const CliOpenFile& cof, void DefaultCliDelegate::exportFiles(DocumentExporter& exporter) { - LOG("Exporting sheet...\n"); + LOG("APP: Exporting sheet...\n"); base::UniquePtr spriteSheet(exporter.exportSheet()); // Sprite sheet isn't used, we just delete it. - LOG("Export sprite sheet: Done\n"); + LOG("APP: Export sprite sheet: Done\n"); } void DefaultCliDelegate::execScript(const std::string& filename) diff --git a/src/app/cmd.cpp b/src/app/cmd.cpp index 17201e52d..f96673844 100644 --- a/src/app/cmd.cpp +++ b/src/app/cmd.cpp @@ -31,7 +31,7 @@ Cmd::~Cmd() void Cmd::execute(Context* ctx) { #if TRACE_CMD - TRACE("Cmd: Executing cmd '%s'\n", typeid(*this).name()); + TRACE("CMD: Executing cmd '%s'\n", typeid(*this).name()); #endif ASSERT(m_state == State::NotExecuted); @@ -48,7 +48,7 @@ void Cmd::execute(Context* ctx) void Cmd::undo() { #if TRACE_CMD - TRACE("Cmd: Undo cmd '%s'\n", typeid(*this).name()); + TRACE("CMD: Undo cmd '%s'\n", typeid(*this).name()); #endif ASSERT(m_state == State::Executed || m_state == State::Redone); @@ -63,7 +63,7 @@ void Cmd::undo() void Cmd::redo() { #if TRACE_CMD - TRACE("Cmd: Redo cmd '%s'\n", typeid(*this).name()); + TRACE("CMD: Redo cmd '%s'\n", typeid(*this).name()); #endif ASSERT(m_state == State::Undone); diff --git a/src/app/commands/cmd_cel_properties.cpp b/src/app/commands/cmd_cel_properties.cpp index 4e2edde64..8280f1b3a 100644 --- a/src/app/commands/cmd_cel_properties.cpp +++ b/src/app/commands/cmd_cel_properties.cpp @@ -125,7 +125,9 @@ private: case kKeyDownMessage: if (opacity()->hasFocus()) { - if (static_cast(msg)->scancode() == kKeyEnter) { + KeyScancode scancode = static_cast(msg)->scancode(); + if (scancode == kKeyEnter || + scancode == kKeyEsc) { onCommitChange(); closeWindow(this); return true; diff --git a/src/app/commands/cmd_layer_properties.cpp b/src/app/commands/cmd_layer_properties.cpp index 972d6d960..4f44c4fd5 100644 --- a/src/app/commands/cmd_layer_properties.cpp +++ b/src/app/commands/cmd_layer_properties.cpp @@ -139,7 +139,9 @@ private: if (name()->hasFocus() || opacity()->hasFocus() || mode()->hasFocus()) { - if (static_cast(msg)->scancode() == kKeyEnter) { + KeyScancode scancode = static_cast(msg)->scancode(); + if (scancode == kKeyEnter || + scancode == kKeyEsc) { onCommitChange(); closeWindow(this); return true; diff --git a/src/app/context.cpp b/src/app/context.cpp index 285694cf0..8784425bb 100644 --- a/src/app/context.cpp +++ b/src/app/context.cpp @@ -60,7 +60,7 @@ void Context::executeCommand(Command* command, const Params& params) ASSERT(command != NULL); - LOG("Context: Executing command '%s'...\n", command->id().c_str()); + LOG(VERBOSE) << "CTXT: Executing command " << command->id() << "\n"; try { m_flags.update(this); @@ -70,14 +70,14 @@ void Context::executeCommand(Command* command, const Params& params) BeforeCommandExecution(ev); if (ev.isCanceled()) { - LOG("Context: '%s' was canceled/simulated.\n", command->id().c_str()); + LOG(VERBOSE) << "CTXT: Command " << command->id() << " was canceled/simulated.\n"; } else if (command->isEnabled(this)) { command->execute(this); - LOG("Context: '%s' executed successfully\n", command->id().c_str()); + LOG(VERBOSE) << "CTXT: Command " << command->id() << " executed successfully\n"; } else { - LOG("Context: '%s' is disabled\n", command->id().c_str()); + LOG(VERBOSE) << "CTXT: Command " << command->id() << " is disabled\n"; } AfterCommandExecution(ev); @@ -87,21 +87,20 @@ void Context::executeCommand(Command* command, const Params& params) app_rebuild_documents_tabs(); } catch (base::Exception& e) { - LOG("Context: Exception caught executing '%s' command\n%s\n", - command->id().c_str(), e.what()); + LOG(ERROR) << "CTXT: Exception caught executing " << command->id() << " command\n" + << e.what() << "\n"; Console::showException(e); } catch (std::exception& e) { - LOG("Context: std::exception caught executing '%s' command\n%s\n", - command->id().c_str(), e.what()); + LOG(ERROR) << "CTXT: std::exception caught executing " << command->id() << " command\n" + << e.what() << "\n"; console.printf("An error ocurred executing the command.\n\nDetails:\n%s", e.what()); } #ifdef NDEBUG catch (...) { - LOG("Context: Unknown exception executing '%s' command\n", - command->id().c_str()); + LOG(ERROR) << "CTXT: Unknown exception executing " << command->id() << " command\n"; console.printf("An unknown error ocurred executing the command.\n" "Please save your work, close the program, try it\n" diff --git a/src/app/crash/backup_observer.cpp b/src/app/crash/backup_observer.cpp index f4191a194..29889e16b 100644 --- a/src/app/crash/backup_observer.cpp +++ b/src/app/crash/backup_observer.cpp @@ -47,14 +47,14 @@ void BackupObserver::stop() void BackupObserver::onAddDocument(doc::Document* document) { - TRACE("DataRecovery: Observe document %p\n", document); + TRACE("RECO: Observe document %p\n", document); base::scoped_lock hold(m_mutex); m_documents.push_back(static_cast(document)); } void BackupObserver::onRemoveDocument(doc::Document* document) { - TRACE("DataRecovery:: Remove document %p\n", document); + TRACE("RECO:: Remove document %p\n", document); { base::scoped_lock hold(m_mutex); base::remove_from_container(m_documents, static_cast(document)); @@ -77,7 +77,7 @@ void BackupObserver::backgroundThread() while (!m_done) { seconds++; if (seconds >= waitUntil) { - TRACE("DataRecovery: Start backup process for %d documents\n", m_documents.size()); + TRACE("RECO: Start backup process for %d documents\n", m_documents.size()); base::scoped_lock hold(m_mutex); base::Chrono chrono; @@ -89,7 +89,7 @@ void BackupObserver::backgroundThread() m_session->saveDocumentChanges(doc); } catch (const std::exception&) { - TRACE("DataRecovery: Document '%d' is locked\n", doc->id()); + TRACE("RECO: Document '%d' is locked\n", doc->id()); somethingLocked = true; } } @@ -97,7 +97,7 @@ void BackupObserver::backgroundThread() seconds = 0; waitUntil = (somethingLocked ? lockedPeriod: normalPeriod); - TRACE("DataRecovery: Backup process done (%.16g)\n", chrono.elapsed()); + TRACE("RECO: Backup process done (%.16g)\n", chrono.elapsed()); } base::this_thread::sleep_for(1.0); } diff --git a/src/app/crash/data_recovery.cpp b/src/app/crash/data_recovery.cpp index bca1baf56..751607c7d 100644 --- a/src/app/crash/data_recovery.cpp +++ b/src/app/crash/data_recovery.cpp @@ -29,11 +29,11 @@ DataRecovery::DataRecovery(doc::Context* ctx) std::string sessionsDir = rf.getFirstOrCreateDefault(); // Existent sessions - TRACE("DataRecovery: Listing sessions from '%s'\n", sessionsDir.c_str()); + TRACE("RECO: Listing sessions from '%s'\n", sessionsDir.c_str()); for (auto& itemname : base::list_files(sessionsDir)) { std::string itempath = base::join_path(sessionsDir, itemname); if (base::is_directory(itempath)) { - TRACE("- Session '%s' ", itempath.c_str()); + TRACE("RECO: Session '%s' ", itempath.c_str()); SessionPtr session(new Session(itempath)); if (!session->isRunning()) { @@ -78,7 +78,7 @@ DataRecovery::DataRecovery(doc::Context* ctx) m_inProgress.reset(new Session(newSessionDir)); m_inProgress->create(pid); - TRACE("DataRecovery: Session in progress '%s'\n", newSessionDir.c_str()); + TRACE("RECO: Session in progress '%s'\n", newSessionDir.c_str()); m_backup = new BackupObserver(m_inProgress.get(), ctx); } diff --git a/src/app/crash/read_document.cpp b/src/app/crash/read_document.cpp index 6f811a438..b3fea6164 100644 --- a/src/app/crash/read_document.cpp +++ b/src/app/crash/read_document.cpp @@ -140,7 +140,7 @@ private: if (!ver) continue; - TRACE(" - Restoring %s #%d v%d\n", prefix, id, ver); + TRACE("RECO: Restoring %s #%d v%d\n", prefix, id, ver); std::string fn = prefix; fn.push_back('-'); @@ -154,11 +154,11 @@ private: obj = (this->*readMember)(s); if (obj) { - TRACE(" - %s #%d v%d restored successfully\n", prefix, id, ver); + TRACE("RECO: %s #%d v%d restored successfully\n", prefix, id, ver); return obj; } else { - TRACE(" - %s #%d v%d was not restored\n", prefix, id, ver); + TRACE("RECO: %s #%d v%d was not restored\n", prefix, id, ver); } } diff --git a/src/app/crash/session.cpp b/src/app/crash/session.cpp index 8c5d25143..ff86a8c55 100644 --- a/src/app/crash/session.cpp +++ b/src/app/crash/session.cpp @@ -136,8 +136,8 @@ void Session::removeFromDisk() } catch (const std::exception& ex) { (void)ex; - TRACE("Session directory cannot be removed, it's not empty\nError: '%s'\n", - ex.what()); + LOG(ERROR) << "RECO: Session directory cannot be removed, it's not empty.\n" + << " Error: " << ex.what() << "\n"; } } @@ -147,7 +147,7 @@ void Session::saveDocumentChanges(app::Document* doc) app::Context ctx; std::string dir = base::join_path(m_path, base::convert_to(doc->id())); - TRACE("DataRecovery: Saving document '%s'...\n", dir.c_str()); + TRACE("RECO: Saving document '%s'...\n", dir.c_str()); if (!base::is_directory(dir)) base::make_directory(dir); @@ -250,7 +250,7 @@ void Session::deleteDirectory(const std::string& dir) for (auto& item : base::list_files(dir)) { std::string objfn = base::join_path(dir, item); if (base::is_file(objfn)) { - TRACE("DataRecovery: Deleting file '%s'\n", objfn.c_str()); + TRACE("RECO: Deleting file '%s'\n", objfn.c_str()); base::delete_file(objfn); } } diff --git a/src/app/document.cpp b/src/app/document.cpp index 72efba98f..f85ea0610 100644 --- a/src/app/document.cpp +++ b/src/app/document.cpp @@ -8,6 +8,10 @@ #include "config.h" #endif +// Uncomment this line in case that you want TRACE() lock/unlock +// operations. +//#define DEBUG_DOCUMENT_LOCKS + #include "app/document.h" #include "app/app.h" @@ -455,7 +459,10 @@ bool Document::lock(LockType lockType, int timeout) if (m_read_locks == 0 && !m_write_lock) { // We can start writting the sprite... m_write_lock = true; - TRACE("Document::lock: Locked <%d> to write\n", id()); + +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lock: Locked <%d> to write\n", id()); +#endif return true; } break; @@ -467,15 +474,21 @@ bool Document::lock(LockType lockType, int timeout) int delay = MIN(100, timeout); timeout -= delay; - TRACE("Document::lock: wait 100 msecs for <%d>\n", id()); +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lock: wait 100 msecs for <%d>\n", id()); +#endif + base::this_thread::sleep_for(double(delay) / 1000.0); } else break; } - TRACE("Document::lock: Cannot lock <%d> to %s (has %d read locks and %d write locks)\n", +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lock: Cannot lock <%d> to %s (has %d read locks and %d write locks)\n", id(), (lockType == ReadLock ? "read": "write"), m_read_locks, m_write_lock); +#endif + return false; } @@ -489,7 +502,11 @@ bool Document::lockToWrite(int timeout) ASSERT(!m_write_lock); m_read_locks = 0; m_write_lock = true; - TRACE("Document::lockToWrite: Locked <%d> to write\n", id()); + +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lockToWrite: Locked <%d> to write\n", id()); +#endif + return true; } } @@ -498,15 +515,21 @@ bool Document::lockToWrite(int timeout) int delay = MIN(100, timeout); timeout -= delay; - TRACE("Document::lockToWrite: wait 100 msecs for <%d>\n", id()); +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lockToWrite: wait 100 msecs for <%d>\n", id()); +#endif + base::this_thread::sleep_for(double(delay) / 1000.0); } else break; } - TRACE("Document::lockToWrite: Cannot lock <%d> to write (has %d read locks and %d write locks)\n", +#ifdef DEBUG_DOCUMENT_LOCKS + TRACE("DOC: Document::lockToWrite: Cannot lock <%d> to write (has %d read locks and %d write locks)\n", id(), m_read_locks, m_write_lock); +#endif + return false; } diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 2e52aef12..f58ea8f4a 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -162,6 +162,7 @@ private: class AseFormat : public FileFormat { const char* onGetName() const override { return "ase"; } const char* onGetExtensions() const override { return "ase,aseprite"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::ASE_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/bmp_format.cpp b/src/app/file/bmp_format.cpp index ca97ecc24..7d1c05e34 100644 --- a/src/app/file/bmp_format.cpp +++ b/src/app/file/bmp_format.cpp @@ -45,6 +45,7 @@ class BmpFormat : public FileFormat { const char* onGetName() const override { return "bmp"; } const char* onGetExtensions() const override { return "bmp"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::BMP_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/file.cpp b/src/app/file/file.cpp index c76e82009..10df87384 100644 --- a/src/app/file/file.cpp +++ b/src/app/file/file.cpp @@ -28,6 +28,7 @@ #include "base/shared_ptr.h" #include "base/string.h" #include "doc/doc.h" +#include "docio/detect_format.h" #include "render/quantization.h" #include "render/render.h" #include "ui/alert.h" @@ -122,13 +123,10 @@ int save_document(Context* context, doc::Document* document) bool is_static_image_format(const std::string& filename) { - std::string extension = - base::string_to_lower( - base::get_file_extension(filename)); - // Get the format through the extension of the filename - FileFormat* format = FileFormatsManager::instance() - ->getFileFormatByExtension(extension.c_str()); + FileFormat* format = + FileFormatsManager::instance() + ->getFileFormat(docio::detect_format_by_file_extension(filename)); return (format && format->support(FILE_SUPPORT_SEQUENCES)); } @@ -172,10 +170,7 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena if (!fop) return nullptr; - // Get the extension of the filename (in lower case) - std::string extension = base::string_to_lower(base::get_file_extension(filename)); - - LOG("Loading file \"%s\" (%s)\n", filename, extension.c_str()); + LOG("FILE: Loading file \"%s\"\n", filename); // Does file exist? if (!base::is_file(filename)) { @@ -184,12 +179,12 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena } // Get the format through the extension of the filename - fop->m_format = FileFormatsManager::instance() - ->getFileFormatByExtension(extension.c_str()); - + fop->m_format = FileFormatsManager::instance()->getFileFormat( + docio::detect_format(filename)); if (!fop->m_format || !fop->m_format->support(FILE_SUPPORT_LOAD)) { - fop->setError("%s can't load \"%s\" files\n", PACKAGE, extension.c_str()); + fop->setError("%s can't load \"%s\" file (\"%s\")\n", PACKAGE, + filename, base::get_file_extension(filename).c_str()); goto done; } @@ -274,17 +269,15 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context, fop->m_roi = roi; // Get the extension of the filename (in lower case) - std::string extension = base::string_to_lower(base::get_file_extension(filename)); - - LOG("Saving document \"%s\" (%s)\n", filename, extension.c_str()); + LOG("FILE: Saving document \"%s\"\n", filename); // Get the format through the extension of the filename - fop->m_format = FileFormatsManager::instance() - ->getFileFormatByExtension(extension.c_str()); - + fop->m_format = FileFormatsManager::instance()->getFileFormat( + docio::detect_format_by_file_extension(filename)); if (!fop->m_format || !fop->m_format->support(FILE_SUPPORT_SAVE)) { - fop->setError("%s can't save \"%s\" files\n", PACKAGE, extension.c_str()); + fop->setError("%s can't save \"%s\" file (\"%s\")\n", PACKAGE, + filename, base::get_file_extension(filename).c_str()); return fop.release(); } diff --git a/src/app/file/file_format.cpp b/src/app/file/file_format.cpp index 39f81735c..4c3a86632 100644 --- a/src/app/file/file_format.cpp +++ b/src/app/file/file_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -33,6 +33,11 @@ const char* FileFormat::extensions() const return onGetExtensions(); } +docio::FileFormat FileFormat::docioFormat() const +{ + return onGetDocioFormat(); +} + bool FileFormat::load(FileOp* fop) { ASSERT(support(FILE_SUPPORT_LOAD)); diff --git a/src/app/file/file_format.h b/src/app/file/file_format.h index ff74eb899..f9cd4cd56 100644 --- a/src/app/file/file_format.h +++ b/src/app/file/file_format.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -9,6 +9,7 @@ #pragma once #include "base/shared_ptr.h" +#include "docio/file_format.h" #include @@ -44,6 +45,8 @@ namespace app { const char* name() const; // File format name const char* extensions() const; // Extensions (e.g. "jpeg,jpg") + docio::FileFormat docioFormat() const; + bool load(FileOp* fop); #ifdef ENABLE_SAVE bool save(FileOp* fop); @@ -70,6 +73,7 @@ namespace app { protected: virtual const char* onGetName() const = 0; virtual const char* onGetExtensions() const = 0; + virtual docio::FileFormat onGetDocioFormat() const = 0; virtual int onGetFlags() const = 0; virtual bool onLoad(FileOp* fop) = 0; diff --git a/src/app/file/file_formats_manager.cpp b/src/app/file/file_formats_manager.cpp index 9ecd60e29..dd457d8dd 100644 --- a/src/app/file/file_formats_manager.cpp +++ b/src/app/file/file_formats_manager.cpp @@ -13,6 +13,7 @@ #include "app/file/file_format.h" #include "app/file/format_options.h" #include "base/string.h" +#include "docio/detect_format.h" #include #include @@ -93,21 +94,12 @@ FileFormatsList::iterator FileFormatsManager::end() return m_formats.end(); } -FileFormat* FileFormatsManager::getFileFormatByExtension(const char* extension) const +FileFormat* FileFormatsManager::getFileFormat(const docio::FileFormat docioFormat) const { - char buf[512], *tok; - - for (FileFormat* ff : m_formats) { - std::strcpy(buf, ff->extensions()); - - for (tok=std::strtok(buf, ","); tok; - tok=std::strtok(NULL, ",")) { - if (base::utf8_icmp(extension, tok) == 0) - return ff; - } - } - - return NULL; + for (FileFormat* ff : m_formats) + if (ff->docioFormat() == docioFormat) + return ff; + return nullptr; } } // namespace app diff --git a/src/app/file/file_formats_manager.h b/src/app/file/file_formats_manager.h index e5859ff60..884303f5e 100644 --- a/src/app/file/file_formats_manager.h +++ b/src/app/file/file_formats_manager.h @@ -8,6 +8,8 @@ #define APP_FILE_FILE_FORMATS_MANAGER_H_INCLUDED #pragma once +#include "docio/file_format.h" + #include namespace app { @@ -32,7 +34,7 @@ namespace app { FileFormatsList::iterator begin(); FileFormatsList::iterator end(); - FileFormat* getFileFormatByExtension(const char* extension) const; + FileFormat* getFileFormat(const docio::FileFormat docioFormat) const; private: FileFormatsManager(); diff --git a/src/app/file/fli_format.cpp b/src/app/file/fli_format.cpp index 7aff79654..395877ddb 100644 --- a/src/app/file/fli_format.cpp +++ b/src/app/file/fli_format.cpp @@ -27,6 +27,7 @@ using namespace base; class FliFormat : public FileFormat { const char* onGetName() const override { return "flc"; } const char* onGetExtensions() const override{ return "flc,fli"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::FLIC_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/gif_format.cpp b/src/app/file/gif_format.cpp index d7dc60886..f3c9347d6 100644 --- a/src/app/file/gif_format.cpp +++ b/src/app/file/gif_format.cpp @@ -63,6 +63,7 @@ class GifFormat : public FileFormat { const char* onGetName() const override { return "gif"; } const char* onGetExtensions() const override { return "gif"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::GIF_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | @@ -188,8 +189,8 @@ public: , m_remap(256) , m_hasLocalColormaps(false) , m_firstLocalColormap(nullptr) { - TRACE("[GifDecoder] GIF background index=%d\n", (int)m_gifFile->SBackGroundColor); - TRACE("[GifDecoder] GIF global colormap=%d, ncolors=%d\n", + TRACE("GIF: background index=%d\n", (int)m_gifFile->SBackGroundColor); + TRACE("GIF: global colormap=%d, ncolors=%d\n", (m_gifFile->SColorMap ? 1: 0), (m_gifFile->SColorMap ? m_gifFile->SColorMap->ColorCount: 0)); } @@ -309,7 +310,7 @@ private: UniquePtr frameImage( readFrameIndexedImage(frameBounds)); - TRACE("[GifDecoder] Frame[%d] transparent index = %d\n", (int)m_frameNum, m_localTransparentIndex); + TRACE("GIF: Frame[%d] transparent index = %d\n", (int)m_frameNum, m_localTransparentIndex); if (m_frameNum == 0) { if (m_localTransparentIndex >= 0) @@ -324,7 +325,7 @@ private: // Convert the sprite to RGB if we have more than 256 colors if ((m_sprite->pixelFormat() == IMAGE_INDEXED) && (m_sprite->palette(m_frameNum)->size() > 256)) { - TRACE("[GifDecoder] Converting to RGB because we have %d colors\n", + TRACE("GIF: Converting to RGB because we have %d colors\n", m_sprite->palette(m_frameNum)->size()); convertIndexedSpriteToRgb(); @@ -443,7 +444,7 @@ private: int ncolors = colormap->ColorCount; bool isLocalColormap = (m_gifFile->Image.ColorMap ? true: false); - TRACE("[GifDecoder] Local colormap=%d, ncolors=%d\n", isLocalColormap, ncolors); + TRACE("GIF: Local colormap=%d, ncolors=%d\n", isLocalColormap, ncolors); // We'll calculate the list of used colormap indexes in this // frameImage. @@ -526,7 +527,7 @@ private: // Number of colors in the image that aren't in the palette. int missing = (usedNColors - found); - TRACE("[GifDecoder] Bg index=%d,\n" + TRACE("GIF: Bg index=%d,\n" " Local transparent index=%d,\n" " Need extra index to show bg color=%d,\n " " Found colors in palette=%d,\n" @@ -644,7 +645,7 @@ private: m_localTransparentIndex = (extension[1] & 1) ? extension[4]: -1; m_frameDelay = (extension[3] << 8) | extension[2]; - TRACE("[GifDecoder] Disposal method: %d\n Transparent index: %d\n Frame delay: %d\n", + TRACE("GIF: Disposal method: %d\n Transparent index: %d\n Frame delay: %d\n", m_disposalMethod, m_localTransparentIndex, m_frameDelay); } } @@ -1058,7 +1059,7 @@ private: } } - TRACE("[GifEncoder] frameBounds=%d %d %d %d prev=%d %d %d %d next=%d %d %d %d\n", + TRACE("GIF: frameBounds=%d %d %d %d prev=%d %d %d %d next=%d %d %d %d\n", frameBounds.x, frameBounds.y, frameBounds.w, frameBounds.h, prev.x, prev.y, prev.w, prev.h, next.x, next.y, next.w, next.h); diff --git a/src/app/file/ico_format.cpp b/src/app/file/ico_format.cpp index 37be98231..f1fcbdf93 100644 --- a/src/app/file/ico_format.cpp +++ b/src/app/file/ico_format.cpp @@ -26,6 +26,7 @@ using namespace base; class IcoFormat : public FileFormat { const char* onGetName() const override { return "ico"; } const char* onGetExtensions() const override { return "ico"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::ICO_IMAGES; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/jpeg_format.cpp b/src/app/file/jpeg_format.cpp index f4b3abbeb..12b9eb0ac 100644 --- a/src/app/file/jpeg_format.cpp +++ b/src/app/file/jpeg_format.cpp @@ -42,6 +42,7 @@ class JpegFormat : public FileFormat { const char* onGetName() const override { return "jpeg"; } const char* onGetExtensions() const override { return "jpeg,jpg"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::JPEG_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | @@ -88,7 +89,7 @@ static void output_message(j_common_ptr cinfo) (*cinfo->err->format_message)(cinfo, buffer); // Put in the log file if. - LOG("JPEG library: \"%s\"\n", buffer); + LOG(ERROR) << "JPEG: \"" << buffer << "\"\n"; // Leave the message for the application. ((struct error_mgr *)cinfo->err)->fop->setError("%s\n", buffer); diff --git a/src/app/file/palette_file.cpp b/src/app/file/palette_file.cpp index 2193cefd6..9cde0ba8c 100644 --- a/src/app/file/palette_file.cpp +++ b/src/app/file/palette_file.cpp @@ -24,6 +24,7 @@ #include "doc/layer.h" #include "doc/palette.h" #include "doc/sprite.h" +#include "docio/detect_format.h" #include @@ -45,26 +46,34 @@ std::string get_writable_palette_extensions() return buf; } -Palette* load_palette(const char *filename) +Palette* load_palette(const char* filename) { - std::string ext = base::string_to_lower(base::get_file_extension(filename)); - Palette* pal = NULL; + docio::FileFormat docioFormat = docio::detect_format(filename); + Palette* pal = nullptr; + + switch (docioFormat) { + + case docio::FileFormat::COL_PALETTE: + pal = doc::file::load_col_file(filename); + break; + + case docio::FileFormat::GPL_PALETTE: + pal = doc::file::load_gpl_file(filename); + break; + + case docio::FileFormat::HEX_PALETTE: + pal = doc::file::load_hex_file(filename); + break; + + case docio::FileFormat::PAL_PALETTE: + pal = doc::file::load_pal_file(filename); + break; + + default: { + FileFormat* ff = FileFormatsManager::instance()->getFileFormat(docioFormat); + if (!ff || !ff->support(FILE_SUPPORT_LOAD)) + break; - if (ext == "col") { - pal = doc::file::load_col_file(filename); - } - else if (ext == "gpl") { - pal = doc::file::load_gpl_file(filename); - } - else if (ext == "hex") { - pal = doc::file::load_hex_file(filename); - } - else if (ext == "pal") { - pal = doc::file::load_pal_file(filename); - } - else { - FileFormat* ff = FileFormatsManager::instance()->getFileFormatByExtension(ext.c_str()); - if (ff && ff->support(FILE_SUPPORT_LOAD)) { base::UniquePtr fop( FileOp::createLoadDocumentOperation( nullptr, filename, @@ -85,6 +94,7 @@ Palette* load_palette(const char *filename) delete fop->releaseDocument(); fop->done(); } + break; } } @@ -94,26 +104,34 @@ Palette* load_palette(const char *filename) return pal; } -bool save_palette(const char *filename, const Palette* pal, int columns) +bool save_palette(const char* filename, const Palette* pal, int columns) { - std::string ext = base::string_to_lower(base::get_file_extension(filename)); + docio::FileFormat docioFormat = docio::detect_format_by_file_extension(filename); bool success = false; - if (ext == "col") { - success = doc::file::save_col_file(pal, filename); - } - else if (ext == "gpl") { - success = doc::file::save_gpl_file(pal, filename); - } - else if (ext == "hex") { - success = doc::file::save_hex_file(pal, filename); - } - else if (ext == "pal") { - success = doc::file::save_pal_file(pal, filename); - } - else { - FileFormat* ff = FileFormatsManager::instance()->getFileFormatByExtension(ext.c_str()); - if (ff && ff->support(FILE_SUPPORT_SAVE)) { + switch (docioFormat) { + + case docio::FileFormat::COL_PALETTE: + success = doc::file::save_col_file(pal, filename); + break; + + case docio::FileFormat::GPL_PALETTE: + success = doc::file::save_gpl_file(pal, filename); + break; + + case docio::FileFormat::HEX_PALETTE: + success = doc::file::save_hex_file(pal, filename); + break; + + case docio::FileFormat::PAL_PALETTE: + success = doc::file::save_pal_file(pal, filename); + break; + + default: { + FileFormat* ff = FileFormatsManager::instance()->getFileFormat(docioFormat); + if (!ff || !ff->support(FILE_SUPPORT_SAVE)) + break; + int w = (columns > 0 ? MID(0, columns, pal->size()): pal->size()); int h = (pal->size() / w) + (pal->size() % w > 0 ? 1: 0); @@ -150,6 +168,7 @@ bool save_palette(const char *filename, const Palette* pal, int columns) doc->close(); delete doc; + break; } } diff --git a/src/app/file/pcx_format.cpp b/src/app/file/pcx_format.cpp index 35a484d97..881c30764 100644 --- a/src/app/file/pcx_format.cpp +++ b/src/app/file/pcx_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -24,6 +24,7 @@ using namespace base; class PcxFormat : public FileFormat { const char* onGetName() const override { return "pcx"; } const char* onGetExtensions() const override { return "pcx"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PCX_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/pixly_format.cpp b/src/app/file/pixly_format.cpp index 8eb072d1d..f0ada2e6e 100644 --- a/src/app/file/pixly_format.cpp +++ b/src/app/file/pixly_format.cpp @@ -31,6 +31,7 @@ using namespace base; class PixlyFormat : public FileFormat { const char* onGetName() const override { return "anim"; } const char* onGetExtensions() const override { return "anim"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PIXLY_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/png_format.cpp b/src/app/file/png_format.cpp index 576e5ac5d..dd4ed596e 100644 --- a/src/app/file/png_format.cpp +++ b/src/app/file/png_format.cpp @@ -29,6 +29,7 @@ using namespace base; class PngFormat : public FileFormat { const char* onGetName() const override { return "png"; } const char* onGetExtensions() const override { return "png"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PNG_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/tga_format.cpp b/src/app/file/tga_format.cpp index 211b59311..ee09ab4c2 100644 --- a/src/app/file/tga_format.cpp +++ b/src/app/file/tga_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -25,6 +25,7 @@ using namespace base; class TgaFormat : public FileFormat { const char* onGetName() const override { return "tga"; } const char* onGetExtensions() const override { return "tga"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::TARGA_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/webp_format.cpp b/src/app/file/webp_format.cpp index 8f38cdc59..255e3b38a 100644 --- a/src/app/file/webp_format.cpp +++ b/src/app/file/webp_format.cpp @@ -41,6 +41,7 @@ class WebPFormat : public FileFormat { const char* onGetName() const override { return "webp"; } const char* onGetExtensions() const override { return "webp"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::WEBP_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file_system.cpp b/src/app/file_system.cpp index 6c1e0e390..b84acc9e5 100644 --- a/src/app/file_system.cpp +++ b/src/app/file_system.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -164,13 +164,10 @@ FileSystemModule::FileSystemModule() // get the root element of the file system (this will create // the 'rootitem' FileItem) getRootFileItem(); - - LOG("File system module installed\n"); } FileSystemModule::~FileSystemModule() { - LOG("File system module: uninstalling\n"); ASSERT(m_instance == this); for (FileItemMap::iterator @@ -197,7 +194,6 @@ FileSystemModule::~FileSystemModule() delete fileitems_map; delete thumbnail_map; - LOG("File system module: uninstalled\n"); m_instance = NULL; } @@ -564,7 +560,7 @@ FileItem::FileItem(FileItem* parent) FileItem::~FileItem() { - LOG("FS: Destroying FileItem() with parent %p\n", m_parent); + TRACE("FS: Destroying FileItem() with parent %p\n", m_parent); #ifdef _WIN32 if (m_fullpidl && m_fullpidl != m_pidl) { diff --git a/src/app/gui_xml.cpp b/src/app/gui_xml.cpp index 745e26c3f..ca0e7771e 100644 --- a/src/app/gui_xml.cpp +++ b/src/app/gui_xml.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -28,7 +28,7 @@ GuiXml* GuiXml::instance() GuiXml::GuiXml() { - LOG("Loading gui.xml file...\n"); + LOG("GUIXML: Loading gui.xml file\n"); ResourceFinder rf; rf.includeDataDir("gui.xml"); diff --git a/src/app/log.cpp b/src/app/log.cpp index 0e985e8a0..e690093d1 100644 --- a/src/app/log.cpp +++ b/src/app/log.cpp @@ -31,7 +31,7 @@ LoggerModule::LoggerModule(bool createLogInDesktop) LoggerModule::~LoggerModule() { - LOG("Logger module: shutting down (this is the last line)\n"); + LOG("LOG: Done\n"); // Close log file base::set_log_filename(""); diff --git a/src/app/modules.cpp b/src/app/modules.cpp index 33f722c1c..b076b242e 100644 --- a/src/app/modules.cpp +++ b/src/app/modules.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -41,7 +41,7 @@ LegacyModules::LegacyModules(int requirements) { for (int c=0; c=0; c--) if (module[c].installed) { - LOG("Unstalling module: %s\n", module[c].name); + LOG("MODS: Unstalling module: %s\n", module[c].name); (*module[c].exit)(); module[c].installed = false; } diff --git a/src/app/res/http_loader.cpp b/src/app/res/http_loader.cpp index 6b303fb05..aca5b21ff 100644 --- a/src/app/res/http_loader.cpp +++ b/src/app/res/http_loader.cpp @@ -48,7 +48,7 @@ void HttpLoader::threadHttpRequest() try { base::ScopedValue scoped(m_done, false, true); - LOG("Sending http request to %s...\n", m_url.c_str()); + LOG("HTTP: Sending http request to %s\n", m_url.c_str()); std::string dir = base::join_path(base::get_temp_path(), PACKAGE); base::make_all_directories(dir); @@ -68,13 +68,13 @@ void HttpLoader::threadHttpRequest() m_filename = fn; } - LOG("Response: %d\n", response.status()); + LOG("HTTP: Response: %d\n", response.status()); } catch (const std::exception& e) { - LOG("Unexpected exception sending http request: '%s'\n", e.what()); + LOG(ERROR) << "HTTP: Unexpected exception sending http request: " << e.what() << "\n"; } catch (...) { - LOG("Unexpected unknown exception sending http request\n"); + LOG(ERROR) << "HTTP: Unexpected unknown exception sending http request\n"; } delete m_request; diff --git a/src/app/res/resources_loader.cpp b/src/app/res/resources_loader.cpp index e2835941f..2b841301e 100644 --- a/src/app/res/resources_loader.cpp +++ b/src/app/res/resources_loader.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -27,14 +27,11 @@ ResourcesLoader::ResourcesLoader(ResourcesLoaderDelegate* delegate) , m_cancel(false) , m_thread(base::Bind(&ResourcesLoader::threadLoadResources, this)) { - LOG("ResourcesLoader::ResourcesLoader()\n"); } ResourcesLoader::~ResourcesLoader() { m_thread.join(); - - LOG("ResourcesLoader::~ResourcesLoader()\n"); } void ResourcesLoader::cancel() @@ -55,12 +52,10 @@ bool ResourcesLoader::next(base::UniquePtr& resource) void ResourcesLoader::threadLoadResources() { - LOG("threadLoadResources()\n"); - base::ScopedValue scoped(m_done, false, true); std::string path = m_delegate->resourcesLocation(); - LOG("Loading resources from %s...\n", path.c_str()); + TRACE("RESLOAD: Loading resources from %s...\n", path.c_str()); if (path.empty()) return; diff --git a/src/app/resource_finder.cpp b/src/app/resource_finder.cpp index 43f3446fd..491a88cb0 100644 --- a/src/app/resource_finder.cpp +++ b/src/app/resource_finder.cpp @@ -57,7 +57,7 @@ bool ResourceFinder::findFirst() { while (next()) { if (m_log) - LOG("Searching file \"%s\"...", filename().c_str()); + LOG("FIND: \"%s\"", filename().c_str()); if (base::is_file(filename())) { if (m_log) @@ -142,7 +142,7 @@ void ResourceFinder::includeHomeDir(const char* filename) addPath(buf); } else { - LOG("You don't have set $HOME variable\n"); + LOG("FIND: You don't have set $HOME variable\n"); addPath(filename); } diff --git a/src/app/tools/tool_box.cpp b/src/app/tools/tool_box.cpp index dfbe1fdb4..0bec93fc2 100644 --- a/src/app/tools/tool_box.cpp +++ b/src/app/tools/tool_box.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -81,8 +81,6 @@ const char* WellKnownPointShapes::Spray = "spray"; ToolBox::ToolBox() { - LOG("Toolbox module: installing\n"); - m_inks[WellKnownInks::Selection] = new SelectionInk(); m_inks[WellKnownInks::Paint] = new PaintInk(PaintInk::Simple); m_inks[WellKnownInks::PaintFg] = new PaintInk(PaintInk::WithFg); @@ -122,8 +120,6 @@ ToolBox::ToolBox() m_intertwiners[WellKnownIntertwiners::AsPixelPerfect] = new IntertwineAsPixelPerfect(); loadTools(); - - LOG("Toolbox module: installed\n"); } struct deleter { @@ -136,16 +132,12 @@ struct deleter { ToolBox::~ToolBox() { - LOG("Toolbox module: uninstalling\n"); - std::for_each(m_tools.begin(), m_tools.end(), deleter()); std::for_each(m_groups.begin(), m_groups.end(), deleter()); std::for_each(m_intertwiners.begin(), m_intertwiners.end(), deleter()); std::for_each(m_pointshapers.begin(), m_pointshapers.end(), deleter()); std::for_each(m_controllers.begin(), m_controllers.end(), deleter()); std::for_each(m_inks.begin(), m_inks.end(), deleter()); - - LOG("Toolbox module: uninstalled\n"); } Tool* ToolBox::getToolById(const std::string& id) @@ -155,9 +147,7 @@ Tool* ToolBox::getToolById(const std::string& id) if (tool->getId() == id) return tool; } - // LOG("Error get_tool_by_name() with '%s'\n", name.c_str()); - // ASSERT(false); - return NULL; + return nullptr; } Ink* ToolBox::getInkById(const std::string& id) @@ -177,7 +167,7 @@ PointShape* ToolBox::getPointShapeById(const std::string& id) void ToolBox::loadTools() { - LOG("Loading Aseprite tools\n"); + LOG("TOOL: Loading tools...\n"); XmlDocumentRef doc(GuiXml::instance()->doc()); TiXmlHandle handle(doc.get()); @@ -188,11 +178,11 @@ void ToolBox::loadTools() const char* group_id = xmlGroup->Attribute("id"); const char* group_text = xmlGroup->Attribute("text"); - LOG(" - New group '%s'\n", group_id); - if (!group_id || !group_text) throw base::Exception("The configuration file has a without 'id' or 'text' attributes."); + LOG(VERBOSE) << "TOOL: Group " << group_id << "\n"; + ToolGroup* tool_group = new ToolGroup(group_id, group_text); // For each tool @@ -207,7 +197,7 @@ void ToolBox::loadTools() Tool* tool = new Tool(tool_group, tool_id, tool_text, tool_tips, default_brush_size ? strtol(default_brush_size, NULL, 10): 1); - LOG(" - New tool '%s' in group '%s' found\n", tool_id, group_id); + LOG(VERBOSE) << "TOOL: Tool " << tool_id << " in group " << group_id << " found\n"; loadToolProperties(xmlTool, tool, 0, "left"); loadToolProperties(xmlTool, tool, 1, "right"); @@ -220,6 +210,8 @@ void ToolBox::loadTools() m_groups.push_back(tool_group); xmlGroup = xmlGroup->NextSiblingElement(); } + + LOG("TOOL: Done. %d tools, %d groups.\n", m_tools.size(), m_groups.size()); } void ToolBox::loadToolProperties(TiXmlElement* xmlTool, Tool* tool, int button, const std::string& suffix) diff --git a/src/app/ui/editor/moving_pixels_state.cpp b/src/app/ui/editor/moving_pixels_state.cpp index c4a90fd18..2524f3ff8 100644 --- a/src/app/ui/editor/moving_pixels_state.cpp +++ b/src/app/ui/editor/moving_pixels_state.cpp @@ -144,7 +144,7 @@ void MovingPixelsState::onEnterState(Editor* editor) EditorState::LeaveAction MovingPixelsState::onLeaveState(Editor* editor, EditorState* newState) { - LOG("MovingPixels: leave state\n"); + TRACE("MOVPIXS: onLeaveState\n"); ASSERT(m_pixelsMovement); ASSERT(editor == m_editor); @@ -481,7 +481,7 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev) { Command* command = ev.command(); - LOG("MovingPixelsState::onBeforeCommandExecution %s\n", command->id().c_str()); + TRACE("MOVPIXS: onBeforeCommandExecution %s\n", command->id().c_str()); // If the command is for other editor, we don't drop pixels. if (!isActiveEditor()) @@ -637,7 +637,7 @@ void MovingPixelsState::setTransparentColor(bool opaque, const app::Color& color void MovingPixelsState::dropPixels() { - LOG("MovingPixels: drop pixels\n"); + TRACE("MOVPIXS: dropPixels\n"); // Just change to default state (StandbyState generally). We'll // receive an onLeaveState() event after this call. diff --git a/src/app/ui/file_selector.cpp b/src/app/ui/file_selector.cpp index e1ab0d0d2..a5da99ad5 100644 --- a/src/app/ui/file_selector.cpp +++ b/src/app/ui/file_selector.cpp @@ -437,7 +437,7 @@ std::string FileSelector::show( if (!start_folder) start_folder = fs->getFileItemFromPath(start_folder_path); - LOG("start_folder_path = %s (%p)\n", start_folder_path.c_str(), start_folder); + TRACE("FILESEL: Start folder '%s' (%p)\n", start_folder_path.c_str(), start_folder); setMinSize(gfx::Size(ui::display_w()*9/10, ui::display_h()*9/10)); remapWindow(); diff --git a/src/app/ui/keyboard_shortcuts.cpp b/src/app/ui/keyboard_shortcuts.cpp index 310f5c8a8..08858194a 100644 --- a/src/app/ui/keyboard_shortcuts.cpp +++ b/src/app/ui/keyboard_shortcuts.cpp @@ -383,7 +383,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source) if (tool) { Key* key = this->tool(tool); if (key && tool_key) { - LOG(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key); + LOG(VERBOSE) << "KEYS: Shortcut for tool " << tool_id << ": " << tool_key << "\n"; Accelerator accel(tool_key); if (!removed) @@ -411,7 +411,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source) if (tool) { Key* key = this->quicktool(tool); if (key && tool_key) { - LOG(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key); + LOG(VERBOSE) << "KEYS: Shortcut for quicktool " << tool_id << ": " << tool_key << "\n"; Accelerator accel(tool_key); if (!removed) @@ -439,7 +439,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source) if (action != KeyAction::None) { Key* key = this->action(action); if (key && tool_key) { - LOG(" - Shortcut for action '%s': <%s>\n", tool_action, tool_key); + LOG(VERBOSE) << "KEYS: Shortcut for action " << tool_action << ": " << tool_key << "\n"; Accelerator accel(tool_key); if (!removed) diff --git a/src/app/ui/resources_listbox.cpp b/src/app/ui/resources_listbox.cpp index a96dbe754..0908f52d8 100644 --- a/src/app/ui/resources_listbox.cpp +++ b/src/app/ui/resources_listbox.cpp @@ -180,8 +180,6 @@ void ResourcesListBox::onTick() if (!m_resourcesLoader->next(resource)) { if (m_resourcesLoader->isDone()) { stop(); - - LOG("Done\n"); } return; } diff --git a/src/app/ui/skin/skin_theme.cpp b/src/app/ui/skin/skin_theme.cpp index c126f5ebc..b6d8cad04 100644 --- a/src/app/ui/skin/skin_theme.cpp +++ b/src/app/ui/skin/skin_theme.cpp @@ -8,6 +8,7 @@ #include "config.h" #endif +#include "app/console.h" #include "app/modules/gui.h" #include "app/pref/preferences.h" #include "app/resource_finder.h" @@ -191,12 +192,27 @@ void SkinTheme::onRegenerate() loadAll(pref.theme.selected.defaultValue()); // Then we load the selected theme to redefine default theme parts. - if (pref.theme.selected.defaultValue() != pref.theme.selected()) - loadAll(pref.theme.selected()); + if (pref.theme.selected.defaultValue() != pref.theme.selected()) { + try { + loadAll(pref.theme.selected()); + } + catch (const std::exception& e) { + LOG("SKIN: Error loading user-theme: %s\n", e.what()); + + if (CurrentTheme::get()) + Console::showException(e); + + // We can continue, as we've already loaded the default theme + // anyway. Here we restore the setting to its default value. + pref.theme.selected(pref.theme.selected.defaultValue()); + } + } } void SkinTheme::loadAll(const std::string& skinId) { + LOG("SKIN: Loading theme %s\n", skinId.c_str()); + loadSheet(skinId); loadFonts(skinId); loadXml(skinId); @@ -204,13 +220,6 @@ void SkinTheme::loadAll(const std::string& skinId) void SkinTheme::loadSheet(const std::string& skinId) { - TRACE("SkinTheme::loadSheet(%s)\n", skinId.c_str()); - - if (m_sheet) { - m_sheet->dispose(); - m_sheet = NULL; - } - // Load the skin sheet std::string sheet_filename("skins/" + skinId + "/sheet.png"); @@ -220,6 +229,10 @@ void SkinTheme::loadSheet(const std::string& skinId) throw base::Exception("File %s not found", sheet_filename.c_str()); try { + if (m_sheet) { + m_sheet->dispose(); + m_sheet = nullptr; + } m_sheet = she::instance()->loadRgbaSurface(rf.filename().c_str()); } catch (...) { @@ -229,8 +242,6 @@ void SkinTheme::loadSheet(const std::string& skinId) void SkinTheme::loadFonts(const std::string& skinId) { - TRACE("SkinTheme::loadFonts(%s)\n", skinId.c_str()); - if (m_defaultFont) m_defaultFont->dispose(); if (m_miniFont) m_miniFont->dispose(); @@ -242,8 +253,6 @@ void SkinTheme::loadFonts(const std::string& skinId) void SkinTheme::loadXml(const std::string& skinId) { - TRACE("SkinTheme::loadXml(%s)\n", skinId.c_str()); - // Load the skin XML std::string xml_filename = "skins/" + skinId + "/skin.xml"; ResourceFinder rf; @@ -264,7 +273,7 @@ void SkinTheme::loadXml(const std::string& skinId) std::string id = xmlDim->Attribute("id"); uint32_t value = strtol(xmlDim->Attribute("value"), NULL, 10); - LOG("Loading dimension '%s'...\n", id.c_str()); + LOG(VERBOSE) << "SKIN: Loading dimension '" << id << "\n"; m_dimensions_by_id[id] = value; xmlDim = xmlDim->NextSiblingElement(); @@ -285,7 +294,7 @@ void SkinTheme::loadXml(const std::string& skinId) (value & 0xff00) >> 8, (value & 0xff)); - LOG("Loading color '%s'...\n", id.c_str()); + LOG(VERBOSE) << "SKIN: Loading color " << id << "\n"; m_colors_by_id[id] = color; xmlColor = xmlColor->NextSiblingElement(); @@ -308,7 +317,7 @@ void SkinTheme::loadXml(const std::string& skinId) int focusy = strtol(xmlCursor->Attribute("focusy"), NULL, 10); int c; - LOG("Loading cursor '%s'...\n", id.c_str()); + LOG(VERBOSE) << "SKIN: Loading cursor " << id << "\n"; for (c=0; cAttribute("id"); + const char* id = xmlIcon->Attribute("id"); int x = strtol(xmlIcon->Attribute("x"), NULL, 10); int y = strtol(xmlIcon->Attribute("y"), NULL, 10); int w = strtol(xmlIcon->Attribute("w"), NULL, 10); int h = strtol(xmlIcon->Attribute("h"), NULL, 10); - LOG("Loading tool icon '%s'...\n", tool_id); + LOG(VERBOSE) << "SKIN: Loading tool icon " << id << "\n"; // Crop the tool-icon from the sheet - m_toolicon[tool_id] = sliceSheet( - m_toolicon[tool_id], gfx::Rect(x, y, w, h)); + m_toolicon[id] = sliceSheet( + m_toolicon[id], gfx::Rect(x, y, w, h)); xmlIcon = xmlIcon->NextSiblingElement(); } @@ -371,7 +380,7 @@ void SkinTheme::loadXml(const std::string& skinId) int w = xmlPart->Attribute("w") ? strtol(xmlPart->Attribute("w"), NULL, 10): 0; int h = xmlPart->Attribute("h") ? strtol(xmlPart->Attribute("h"), NULL, 10): 0; - LOG("Loading part '%s'...\n", part_id); + LOG(VERBOSE) << "SKIN: Loading part " << part_id << "\n"; SkinPartPtr part = m_parts_by_id[part_id]; if (!part) @@ -424,7 +433,8 @@ void SkinTheme::loadXml(const std::string& skinId) while (xmlRule) { const std::string ruleName = xmlRule->Value(); - LOG("- Rule '%s' for '%s'\n", ruleName.c_str(), style_id); + LOG(VERBOSE) << "SKIN: Rule " << ruleName + << " for " << style_id << "\n"; // TODO This code design to read styles could be improved. diff --git a/src/app/ui/timeline.cpp b/src/app/ui/timeline.cpp index 81094099a..9b1ef78c2 100644 --- a/src/app/ui/timeline.cpp +++ b/src/app/ui/timeline.cpp @@ -145,9 +145,6 @@ Timeline::Timeline() , m_offset_count(0) , m_scroll(false) , m_fromTimeline(false) - , m_thumbnailsOverlayVisible(false) - , m_thumbnailsOverlayDirection(int(frameBoxWidth()*1.0), - int(frameBoxWidth()*0.5)) { enableFlags(CTRL_RIGHT_CLICK); @@ -181,13 +178,26 @@ Timeline::~Timeline() void Timeline::setZoom(double zoom) { m_zoom = MID(1.0, zoom, 10.0); + m_thumbnailsOverlayDirection = gfx::Point(int(frameBoxWidth()*1.0), int(frameBoxWidth()*0.5)); + m_thumbnailsOverlayVisible = false; +} + +void Timeline::setZoomAndUpdate(double zoom) +{ + if (zoom != m_zoom) { + setZoom(zoom); + updateScrollBars(); + setViewScroll(viewScroll()); + invalidate(); + } + if (zoom != docPref().thumbnails.zoom()) { + docPref().thumbnails.zoom(zoom); + } } void Timeline::onThumbnailsPrefChange() { - setZoom(docPref().thumbnails.zoom()); - m_thumbnailsOverlayDirection = gfx::Point(int(frameBoxWidth()*1.0), int(frameBoxWidth()*0.5)); - invalidate(); + setZoomAndUpdate(docPref().thumbnails.zoom()); } void Timeline::updateUsingEditor(Editor* editor) @@ -1055,23 +1065,35 @@ bool Timeline::onProcessMessage(Message* msg) case kMouseWheelMessage: if (m_document) { - int dz = static_cast(msg)->wheelDelta().y; - int dx = 0; - int dy = 0; + int base_size = skinTheme()->dimensions.timelineBaseSize(); + int dz = static_cast(msg)->wheelDelta().y * base_size; - dx += static_cast(msg)->wheelDelta().x; - - if (msg->ctrlPressed()) - dx = dz * frameBoxWidth(); - else - dy = dz * layerBoxHeight(); - - if (msg->shiftPressed()) { - dx *= 3; - dy *= 3; + if (msg->altPressed()) { + if (dz != 0) { + double next_zoom = m_zoom + (dz < 0 ? 1 : -1); + setZoomAndUpdate(next_zoom); + } } + else { + int dx; + int dy; - setViewScroll(viewScroll() + gfx::Point(dx, dy)); + if (msg->ctrlPressed()) { + dx = dz; + dy = 0; + } + else { + dx = static_cast(msg)->wheelDelta().x * base_size; + dy = dz; + } + + if (msg->shiftPressed()) { + dx *= frameBoxWidth() / base_size; + dy *= layerBoxHeight() / base_size; + } + + setViewScroll(viewScroll() + gfx::Point(dx, dy)); + } } break; @@ -1083,8 +1105,7 @@ bool Timeline::onProcessMessage(Message* msg) break; case kTouchMagnifyMessage: - setZoom(m_zoom + m_zoom * static_cast(msg)->magnification()); - invalidate(); + setZoomAndUpdate(m_zoom + m_zoom * static_cast(msg)->magnification()); break; } @@ -3032,22 +3053,22 @@ gfx::Size Timeline::celBoxSize() const int Timeline::headerBoxWidth() const { - return int(12 * guiscale()); + return int(skinTheme()->dimensions.timelineBaseSize() * guiscale()); } int Timeline::headerBoxHeight() const { - return int(12 * guiscale()); + return int(skinTheme()->dimensions.timelineBaseSize() * guiscale()); } int Timeline::layerBoxHeight() const { - return int(m_zoom*12*guiscale() + (int)(m_zoom > 1) * headerBoxHeight()); + return int(m_zoom*skinTheme()->dimensions.timelineBaseSize()*guiscale() + (int)(m_zoom > 1) * headerBoxHeight()); } int Timeline::frameBoxWidth() const { - return int(m_zoom*12*guiscale()); + return int(m_zoom*skinTheme()->dimensions.timelineBaseSize()*guiscale()); } int Timeline::outlineWidth() const diff --git a/src/app/ui/timeline.h b/src/app/ui/timeline.h index 3003301c3..99d86a0ec 100644 --- a/src/app/ui/timeline.h +++ b/src/app/ui/timeline.h @@ -311,6 +311,7 @@ namespace app { void drawCelOverlay(ui::Graphics* g); void onThumbnailsPrefChange(); void setZoom(double zoom); + void setZoomAndUpdate(double zoom); ui::ScrollBar m_hbar; ui::ScrollBar m_vbar; diff --git a/src/base/dll_unix.h b/src/base/dll_unix.h index 8ea429495..3191119fc 100644 --- a/src/base/dll_unix.h +++ b/src/base/dll_unix.h @@ -4,6 +4,7 @@ // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. +#include "base/config.h" #include "base/string.h" #ifdef HAVE_DLFCN_H diff --git a/src/base/log.cpp b/src/base/log.cpp index 674af4b27..9d0b887ed 100644 --- a/src/base/log.cpp +++ b/src/base/log.cpp @@ -89,10 +89,10 @@ std::ostream& base::get_log_stream(LogLevel level) return log_stream; } -void LOG(const char* format, ...) +std::ostream& LOG(const char* format, ...) { if (log_level < INFO) - return; + return null_stream; char buf[2048]; va_list ap; @@ -106,4 +106,5 @@ void LOG(const char* format, ...) #endif va_end(ap); + return log_stream; } diff --git a/src/base/log.h b/src/base/log.h index 104098a67..3e68bab0f 100644 --- a/src/base/log.h +++ b/src/base/log.h @@ -21,9 +21,6 @@ enum LogLevel { VERBOSE = 5, // Information step by step }; -// E.g. LOG("text in information log level\n"); -void LOG(const char* format, ...); - #ifdef __cplusplus #include @@ -36,6 +33,9 @@ namespace base { } // namespace base +// E.g. LOG("text in information log level\n"); +std::ostream& LOG(const char* format, ...); + // E.g. LOG(INFO) << "some information\n"; inline std::ostream& LOG(LogLevel level) { return base::get_log_stream(level); diff --git a/src/base/string.cpp b/src/base/string.cpp index e265ce861..43cf3a898 100644 --- a/src/base/string.cpp +++ b/src/base/string.cpp @@ -8,7 +8,9 @@ #include "config.h" #endif +#include "base/debug.h" #include "base/string.h" + #include #include #include @@ -158,7 +160,7 @@ std::wstring from_utf8(const std::string& src) utf8_const_iterator end(src.end()); while (it != end) { - assert(buf_it != buf_end); + ASSERT(buf_it != buf_end); *buf_it = *it; ++buf_it; ++it; diff --git a/src/base/string.h b/src/base/string.h index cb0d5113e..f0c3ebd07 100644 --- a/src/base/string.h +++ b/src/base/string.h @@ -1,5 +1,5 @@ // Aseprite Base Library -// Copyright (c) 2001-2013, 2015 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -141,6 +141,30 @@ namespace base { } }; + class utf8 { + public: + utf8(std::string& s) : m_begin(utf8_iterator(s.begin())), + m_end(utf8_iterator(s.end())) { + } + const utf8_iterator& begin() const { return m_begin; } + const utf8_iterator& end() const { return m_end; } + private: + utf8_iterator m_begin; + utf8_iterator m_end; + }; + + class utf8_const { + public: + utf8_const(const std::string& s) : m_begin(utf8_const_iterator(s.begin())), + m_end(utf8_const_iterator(s.end())) { + } + const utf8_const_iterator& begin() const { return m_begin; } + const utf8_const_iterator& end() const { return m_end; } + private: + utf8_const_iterator m_begin; + utf8_const_iterator m_end; + }; + } #endif diff --git a/src/base/string_tests.cpp b/src/base/string_tests.cpp index 89ebd5128..3ed8d1b28 100644 --- a/src/base/string_tests.cpp +++ b/src/base/string_tests.cpp @@ -29,6 +29,30 @@ TEST(String, Utf8Conversion) ASSERT_EQ(a, c); } +TEST(String, Utf8Wrapper) +{ + std::string a, b = "abc"; + for (int ch : utf8(b)) + a.push_back(ch); + EXPECT_EQ("abc", a); + + std::string c, d = "def"; + for (int ch : utf8_const(d)) // TODO we should be able to specify a string-literal here + c.push_back(ch); + EXPECT_EQ("def", c); + + int i = 0; + d = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"; + for (int ch : utf8_const(d)) { // 日本語 + switch (i++) { + case 0: EXPECT_EQ(ch, 0x65E5); break; + case 1: EXPECT_EQ(ch, 0x672C); break; + case 2: EXPECT_EQ(ch, 0x8A9E); break; + default: EXPECT_FALSE(true); break; + } + } +} + TEST(String, Utf8Iterator) { std::string a = "Hello"; diff --git a/src/cfg/cfg.cpp b/src/cfg/cfg.cpp index 02df66357..cfbf9f1ea 100644 --- a/src/cfg/cfg.cpp +++ b/src/cfg/cfg.cpp @@ -14,7 +14,8 @@ #include "base/log.h" #include "base/string.h" -#include +#include +#include #include "SimpleIni.h" namespace cfg { @@ -67,8 +68,9 @@ public: base::FileHandle file(base::open_file(m_filename, "rb")); if (file) { SI_Error err = m_ini.LoadFile(file.get()); - if (err != SI_OK) - LOG("Error '%d' loading configuration from '%s'.", err, m_filename.c_str()); + if (err != SI_OK) { + LOG(ERROR) << "CFG: Error " << err << " loading configuration from " << m_filename << "\n"; + } } } @@ -76,8 +78,9 @@ public: base::FileHandle file(base::open_file(m_filename, "wb")); if (file) { SI_Error err = m_ini.SaveFile(file.get()); - if (err != SI_OK) - LOG("Error '%d' saving configuration into '%s'.", err, m_filename.c_str()); + if (err != SI_OK) { + LOG(ERROR) << "CFG: Error " << err << " saving configuration into " << m_filename << "\n"; + } } } diff --git a/src/doc/algorithm/resize_image.cpp b/src/doc/algorithm/resize_image.cpp index 44870ec84..4751c3625 100644 --- a/src/doc/algorithm/resize_image.cpp +++ b/src/doc/algorithm/resize_image.cpp @@ -17,6 +17,8 @@ #include "doc/rgbmap.h" #include "gfx/point.h" +#include + namespace doc { namespace algorithm { @@ -31,9 +33,9 @@ void resize_image_nearest(const Image* src, Image* dst) auto dstIt = dstBits.begin(); for (int y=0; yheight(); ++y) { - py = floor(y * y_ratio); + py = std::floor(y * y_ratio); for (int x=0; xwidth(); ++x, ++dstIt) { - px = floor(x * x_ratio); + px = std::floor(x * x_ratio); *dstIt = get_pixel_fast(src, px, py); } } @@ -69,8 +71,8 @@ void resize_image(const Image* src, Image* dst, ResizeMethod method, const Palet dv = (src->height()-1) * 1.0 / (dst->height()-1); for (y=0; yheight(); ++y) { for (x=0; xwidth(); ++x) { - u_floor = (int)floor(u); - v_floor = (int)floor(v); + u_floor = (int)std::floor(u); + v_floor = (int)std::floor(v); if (u_floor > src->width()-1) { u_floor = src->width()-1; diff --git a/src/doc/documents_observer.h b/src/doc/documents_observer.h index 92593af0e..f4663c618 100644 --- a/src/doc/documents_observer.h +++ b/src/doc/documents_observer.h @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2001-2014 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -13,7 +13,7 @@ namespace doc { class CreateDocumentArgs { public: - CreateDocumentArgs() : m_doc(NULL) { } + CreateDocumentArgs() : m_doc(nullptr) { } Document* document() { return m_doc; } void setDocument(Document* doc) { m_doc = doc; } private: diff --git a/src/doc/file/gpl_file.cpp b/src/doc/file/gpl_file.cpp index 2dc742807..231dc7ba3 100644 --- a/src/doc/file/gpl_file.cpp +++ b/src/doc/file/gpl_file.cpp @@ -9,6 +9,7 @@ #endif #include "base/fstream_path.h" +#include "base/log.h" #include "base/split_string.h" #include "base/trim_string.h" #include "base/unique_ptr.h" @@ -72,7 +73,7 @@ Palette* load_gpl_file(const char *filename) base::trim_string(comment, comment); if (!comment.empty()) { - LOG("%s comment: %s\n", filename, comment.c_str()); + LOG(VERBOSE) << "PAL: " << filename << " comment: " << comment << "\n"; pal->setComment(comment); } diff --git a/src/doc/sprite.cpp b/src/doc/sprite.cpp index b9d296b59..d0b20f9ac 100644 --- a/src/doc/sprite.cpp +++ b/src/doc/sprite.cpp @@ -506,7 +506,6 @@ void Sprite::pickCels(const double x, cels.push_back(cel); } - fflush(stdout); } ////////////////////////////////////////////////////////////////////// diff --git a/src/docio/CMakeLists.txt b/src/docio/CMakeLists.txt new file mode 100644 index 000000000..cf8a2cf6b --- /dev/null +++ b/src/docio/CMakeLists.txt @@ -0,0 +1,9 @@ +# Aseprite Document IO Library +# Copyright (c) 2016 David Capello + +add_library(docio-lib + detect_format.cpp) + +target_link_libraries(docio-lib + flic-lib + base-lib) diff --git a/src/iff/LICENSE.txt b/src/docio/LICENSE.txt similarity index 96% rename from src/iff/LICENSE.txt rename to src/docio/LICENSE.txt index aea0f6e8f..9a182c0f3 100644 --- a/src/iff/LICENSE.txt +++ b/src/docio/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 David Capello +Copyright (c) 2016 David Capello Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/docio/README.md b/src/docio/README.md new file mode 100644 index 000000000..34e04c3c6 --- /dev/null +++ b/src/docio/README.md @@ -0,0 +1,4 @@ +# Aseprite Document IO Library +*Copyright (C) 2016 David Capello* + +> Distributed under [MIT license](LICENSE.txt) diff --git a/src/docio/detect_format.cpp b/src/docio/detect_format.cpp new file mode 100644 index 000000000..686dd881c --- /dev/null +++ b/src/docio/detect_format.cpp @@ -0,0 +1,140 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#include "docio/detect_format.h" + +#include "base/file_handle.h" +#include "base/path.h" +#include "base/string.h" +#include "flic/flic_details.h" + +#include + +#define ASE_MAGIC_NUMBER 0xA5E0 +#define BMP_MAGIC_NUMBER 0x4D42 // "BM" +#define JPG_MAGIC_NUMBER 0xD8FF +#define GIF_87_STAMP "GIF87a" +#define GIF_89_STAMP "GIF89a" +#define PNG_MAGIC_DWORD1 0x474E5089 +#define PNG_MAGIC_DWORD2 0x0A1A0A0D + +namespace docio { + +FileFormat detect_format(const std::string& filename) +{ + FileFormat ff = detect_format_by_file_content(filename); + if (ff == FileFormat::UNKNOWN) + ff = detect_format_by_file_extension(filename); + return ff; +} + +FileFormat detect_format_by_file_content(const std::string& filename) +{ +#define IS_MAGIC_WORD(offset, word) \ + ((buf[offset+0] == (word & 0xff)) && \ + (buf[offset+1] == ((word & 0xff00) >> 8))) + +#define IS_MAGIC_DWORD(offset, dword) \ + ((buf[offset+0] == (dword & 0xff)) && \ + (buf[offset+1] == ((dword & 0xff00) >> 8)) && \ + (buf[offset+2] == ((dword & 0xff0000) >> 16)) && \ + (buf[offset+3] == ((dword & 0xff000000) >> 24))) + + base::FileHandle handle(base::open_file(filename.c_str(), "rb")); + if (!handle) + return FileFormat::ERROR; + + FILE* f = handle.get(); + unsigned char buf[8]; + int count = fread(buf, 1, 8, f); + + if (count >= 2) { + if (IS_MAGIC_WORD(0, BMP_MAGIC_NUMBER)) + return FileFormat::BMP_IMAGE; + + if (IS_MAGIC_WORD(0, JPG_MAGIC_NUMBER)) + return FileFormat::JPEG_IMAGE; + + if (count >= 6) { + if (std::strncmp((const char*)buf, GIF_87_STAMP, 6) == 0 || + std::strncmp((const char*)buf, GIF_89_STAMP, 6) == 0) + return FileFormat::GIF_ANIMATION; + + if (IS_MAGIC_WORD(4, ASE_MAGIC_NUMBER)) + return FileFormat::ASE_ANIMATION; + + if (IS_MAGIC_WORD(4, FLI_MAGIC_NUMBER) || + IS_MAGIC_WORD(4, FLC_MAGIC_NUMBER)) + return FileFormat::FLIC_ANIMATION; + + if (count >= 8) { + if (IS_MAGIC_DWORD(0, PNG_MAGIC_DWORD1) && + IS_MAGIC_DWORD(4, PNG_MAGIC_DWORD2)) + return FileFormat::PNG_IMAGE; + } + } + } + + return FileFormat::UNKNOWN; +} + +FileFormat detect_format_by_file_extension(const std::string& filename) +{ + // By extension + const std::string ext = base::string_to_lower(base::get_file_extension(filename)); + + if (ext == "ase" || + ext == "aseprite") + return FileFormat::ASE_ANIMATION; + + if (ext == "bmp") + return FileFormat::BMP_IMAGE; + + if (ext == "col") + return FileFormat::COL_PALETTE; + + if (ext == "flc" || + ext == "fli") + return FileFormat::FLIC_ANIMATION; + + if (ext == "gif") + return FileFormat::GIF_ANIMATION; + + if (ext == "gpl") + return FileFormat::GPL_PALETTE; + + if (ext == "hex") + return FileFormat::HEX_PALETTE; + + if (ext == "ico") + return FileFormat::ICO_IMAGES; + + if (ext == "jpg" || + ext == "jpeg") + return FileFormat::JPEG_IMAGE; + + if (ext == "pal") + return FileFormat::PAL_PALETTE; + + if (ext == "pcx") + return FileFormat::PCX_IMAGE; + + if (ext == "anim") + return FileFormat::PIXLY_ANIMATION; + + if (ext == "png") + return FileFormat::PNG_IMAGE; + + if (ext == "tga") + return FileFormat::TARGA_IMAGE; + + if (ext == "webp") + return FileFormat::WEBP_ANIMATION; + + return FileFormat::UNKNOWN; +} + +} // namespace docio diff --git a/src/docio/detect_format.h b/src/docio/detect_format.h new file mode 100644 index 000000000..d5a869164 --- /dev/null +++ b/src/docio/detect_format.h @@ -0,0 +1,23 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef DOCIO_DETECT_FORMAT_H_INCLUDED +#define DOCIO_DETECT_FORMAT_H_INCLUDED +#pragma once + +#include "docio/file_format.h" + +#include + +namespace docio { + +FileFormat detect_format(const std::string& filename); +FileFormat detect_format_by_file_content(const std::string& filename); +FileFormat detect_format_by_file_extension(const std::string& filename); + +} // namespace docio + +#endif diff --git a/src/docio/file_format.h b/src/docio/file_format.h new file mode 100644 index 000000000..bbf33b54b --- /dev/null +++ b/src/docio/file_format.h @@ -0,0 +1,37 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef DOCIO_FILE_FORMAT_H_INCLUDED +#define DOCIO_FILE_FORMAT_H_INCLUDED +#pragma once + +namespace docio { + +enum class FileFormat { + ERROR = -1, + UNKNOWN = 0, + + ASE_ANIMATION, // Aseprite File Format + ASE_PALETTE, // Adobe Swatch Exchange + BMP_IMAGE, + COL_PALETTE, + FLIC_ANIMATION, + GIF_ANIMATION, + GPL_PALETTE, + HEX_PALETTE, + ICO_IMAGES, + JPEG_IMAGE, + PAL_PALETTE, + PCX_IMAGE, + PIXLY_ANIMATION, + PNG_IMAGE, + TARGA_IMAGE, + WEBP_ANIMATION, +}; + +} // namespace docio + +#endif diff --git a/src/ft/face.h b/src/ft/face.h index 9612c8bc8..4436aa5d8 100644 --- a/src/ft/face.h +++ b/src/ft/face.h @@ -8,6 +8,7 @@ #define FT_FACE_H_INCLUDED #pragma once +#include "base/debug.h" #include "base/disable_copying.h" #include "base/string.h" #include "ft/freetype_headers.h" diff --git a/src/iff/README.md b/src/iff/README.md deleted file mode 100644 index efe59b660..000000000 --- a/src/iff/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Aseprite Image File Formats Library -*Copyright (C) 2014 David Capello* - -> Distributed under [MIT license](LICENSE.txt) diff --git a/src/she/CMakeLists.txt b/src/she/CMakeLists.txt index 4909ff16a..ea4d8c4a4 100644 --- a/src/she/CMakeLists.txt +++ b/src/she/CMakeLists.txt @@ -82,9 +82,8 @@ if(USE_SKIA_BACKEND) find_library(SKIA_GIF_LIBRARY giflib PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) find_library(SKIA_IMAGES_LIBRARY skia_images PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_JPG_LIBRARY jpeg-turbo NAMES libjpeg-turbo PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) - find_library(SKIA_OPTS_AVX2_LIBRARY skia_opts_avx2 PATH "${SKIA_BUILD_OUT_DIR}") - find_library(SKIA_OPTS_AVX_LIBRARY skia_opts_avx PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_OPTS_AVX_LIBRARY skia_opts_avx PATH "${SKIA_BUILD_OUT_DIR}") + find_library(SKIA_OPTS_HSW_LIBRARY skia_opts_hsw PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_OPTS_LIBRARY skia_opts PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_OPTS_SSE41_LIBRARY skia_opts_sse41 PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_OPTS_SSE42_LIBRARY skia_opts_sse42 PATH "${SKIA_BUILD_OUT_DIR}") @@ -97,7 +96,10 @@ if(USE_SKIA_BACKEND) find_library(SKIA_SKKTX_LIBRARY SkKTX libSkKTX PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) find_library(SKIA_UTILS_LIBRARY skia_utils PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_WEBP_DEC_LIBRARY webp_dec NAMES libwebp_dec PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) + find_library(SKIA_WEBP_DEMUX_LIBRARY webp_demux NAMES libwebp_demux PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) find_library(SKIA_WEBP_DSP_LIBRARY webp_dsp NAMES libwebp_dsp PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) + find_library(SKIA_WEBP_DSP_ENC_LIBRARY webp_dsp_enc NAMES libwebp_dsp_enc PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) + find_library(SKIA_WEBP_ENC_LIBRARY webp_enc NAMES libwebp_enc PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) find_library(SKIA_WEBP_UTILS_LIBRARY webp_utils NAMES libwebp_utils PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) find_library(SKIA_ZLIB_LIBRARY zlib PATHS "${SKIA_BUILD_OUT_DIR}" "${SKIA_BUILD_OUT_DIR}/obj/gyp" NO_DEFAULT_PATH) @@ -153,8 +155,8 @@ if(USE_SKIA_BACKEND) ${SKIA_OPTS_SSSE3_LIBRARY} ${SKIA_OPTS_SSE41_LIBRARY} ${SKIA_OPTS_SSE42_LIBRARY} + ${SKIA_OPTS_HSW_LIBRARY} ${SKIA_OPTS_AVX_LIBRARY} - ${SKIA_OPTS_AVX2_LIBRARY} ${SKIA_PORTS_LIBRARY} ${SKIA_EFFECTS_LIBRARY} ${SKIA_CODEC_LIBRARY} @@ -164,7 +166,10 @@ if(USE_SKIA_BACKEND) ${SKIA_GIF_LIBRARY} ${SKIA_JPG_LIBRARY} ${SKIA_WEBP_DEC_LIBRARY} + ${SKIA_WEBP_DEMUX_LIBRARY} ${SKIA_WEBP_DSP_LIBRARY} + ${SKIA_WEBP_DSP_ENC_LIBRARY} + ${SKIA_WEBP_ENC_LIBRARY} ${SKIA_WEBP_UTILS_LIBRARY} ${SKIA_PNG_LIBRARY} ${SKIA_ZLIB_LIBRARY} @@ -183,6 +188,7 @@ if(USE_SKIA_BACKEND) list(APPEND SHE_SOURCES skia/skia_display.cpp + skia/skia_surface.cpp skia/she.cpp) if(WIN32) diff --git a/src/she/gl/gl_context_egl.h b/src/she/gl/gl_context_egl.h index f4a661cc2..1d0739b12 100644 --- a/src/she/gl/gl_context_egl.h +++ b/src/she/gl/gl_context_egl.h @@ -32,7 +32,7 @@ public: bool createGLContext() override { m_display = getD3DEGLDisplay((HDC)GetDC((HWND)m_nativeDisplay)); if (m_display == EGL_NO_DISPLAY) { - LOG("Cannot create EGL display"); + LOG("OS: Cannot create EGL display"); return false; } diff --git a/src/she/osx/app.mm b/src/she/osx/app.mm index 900ce804f..3156202e7 100644 --- a/src/she/osx/app.mm +++ b/src/she/osx/app.mm @@ -12,6 +12,7 @@ #include "she/osx/app.h" +#include "base/debug.h" #include "base/thread.h" #include "she/osx/app_delegate.h" diff --git a/src/she/osx/window.mm b/src/she/osx/window.mm index b5b737275..92de44367 100644 --- a/src/she/osx/window.mm +++ b/src/she/osx/window.mm @@ -10,6 +10,7 @@ #include "she/osx/window.h" +#include "base/debug.h" #include "she/event.h" #include "she/osx/event_queue.h" #include "she/osx/view.h" diff --git a/src/she/skia/skia_surface.cpp b/src/she/skia/skia_surface.cpp new file mode 100644 index 000000000..9d8beef86 --- /dev/null +++ b/src/she/skia/skia_surface.cpp @@ -0,0 +1,61 @@ +// SHE library +// Copyright (C) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "she/skia/skia_surface.h" + +#include "base/file_handle.h" + +#include "SkCodec.h" +#include "SkPixelRef.h" +#include "SkStream.h" + +namespace she { + +sk_sp SkiaSurface::m_colorSpace; + +// static +Surface* SkiaSurface::loadSurface(const char* filename) +{ + base::FileHandle fp(base::open_file_with_exception(filename, "rb")); + + SkAutoTDelete codec( + SkCodec::NewFromStream( + new SkFILEStream(fp.get(), SkFILEStream::kCallerRetains_Ownership))); + if (!codec) + return nullptr; + + SkImageInfo info = codec->getInfo() + .makeColorType(kN32_SkColorType) + .makeAlphaType(kPremul_SkAlphaType) + .makeColorSpace(colorSpace()); + SkBitmap bm; + if (!bm.tryAllocPixels(info)) + return nullptr; + + const SkCodec::Result r = codec->getPixels(info, bm.getPixels(), bm.rowBytes()); + if (r != SkCodec::kSuccess) + return nullptr; + + SkiaSurface* sur = new SkiaSurface(); + sur->swapBitmap(bm); + return sur; +} + +// static +sk_sp SkiaSurface::colorSpace() +{ +#if 0 // TODO Add support to different color spaces + if (!m_colorSpace) + m_colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); +#endif + return m_colorSpace; +} + +} // namespace she diff --git a/src/she/skia/skia_surface.h b/src/she/skia/skia_surface.h index 0c67492b0..84a2ee082 100644 --- a/src/she/skia/skia_surface.h +++ b/src/she/skia/skia_surface.h @@ -59,7 +59,8 @@ public: ASSERT(!m_surface); if (!m_bitmap.tryAllocPixels( - SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType))) + SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType, + colorSpace()))) throw base::Exception("Cannot create Skia surface"); m_bitmap.eraseColor(SK_ColorTRANSPARENT); @@ -70,7 +71,7 @@ public: ASSERT(!m_surface); if (!m_bitmap.tryAllocPixels( - SkImageInfo::MakeN32Premul(width, height))) + SkImageInfo::MakeN32Premul(width, height, colorSpace()))) throw base::Exception("Cannot create Skia surface"); m_bitmap.eraseColor(SK_ColorTRANSPARENT); @@ -112,30 +113,30 @@ public: void setClipBounds(const gfx::Rect& rc) override { m_clip = rc; - m_canvas->clipRect(SkRect::Make(to_skia(m_clip)), SkRegion::kReplace_Op); + m_canvas->clipRect(SkRect::Make(to_skia(m_clip)), kReplace_SkClipOp); } bool intersectClipRect(const gfx::Rect& rc) override { m_clip &= rc; - m_canvas->clipRect(SkRect::Make(to_skia(m_clip)), SkRegion::kReplace_Op); + m_canvas->clipRect(SkRect::Make(to_skia(m_clip)), kReplace_SkClipOp); return !m_clip.isEmpty(); } void setDrawMode(DrawMode mode, int param) override { switch (mode) { case DrawMode::Solid: - m_paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + m_paint.setBlendMode(SkBlendMode::kSrcOver); m_paint.setShader(nullptr); break; case DrawMode::Xor: - m_paint.setXfermodeMode(SkXfermode::kXor_Mode); + m_paint.setBlendMode(SkBlendMode::kXor); m_paint.setShader(nullptr); break; case DrawMode::Checked: { - m_paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + m_paint.setBlendMode(SkBlendMode::kSrcOver); { SkBitmap bitmap; - if (!bitmap.tryAllocPixels(SkImageInfo::MakeN32Premul(8, 8))) + if (!bitmap.tryAllocPixels(SkImageInfo::MakeN32Premul(8, 8, colorSpace()))) throw base::Exception("Cannot create temporary Skia surface"); { @@ -184,7 +185,7 @@ public: throw base::Exception("Cannot create temporary Skia surface to change scale"); SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); + paint.setBlendMode(SkBlendMode::kSrc); SkCanvas canvas(result); SkRect srcRect = SkRect::Make(SkIRect::MakeXYWH(0, 0, width(), height())); @@ -270,7 +271,7 @@ public: SkColor c = 0; if (m_surface) { - SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(1, 1); + SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(1, 1, colorSpace()); uint32_t dstPixels; if (m_canvas->readPixels(dstInfo, &dstPixels, 4, x, y)) c = dstPixels; @@ -324,7 +325,7 @@ public: } void blitTo(Surface* dest, int srcx, int srcy, int dstx, int dsty, int width, int height) const override { - SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); + SkImageInfo info = SkImageInfo::MakeN32Premul(width, height, colorSpace()); std::vector pixels(width * height * 4); m_canvas->readPixels(info, (void*)&pixels[0], 4*width, srcx, srcy); static_cast(dest) @@ -382,7 +383,7 @@ public: SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h)); SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); + paint.setBlendMode(SkBlendMode::kSrc); m_canvas->drawBitmapRect( ((SkiaSurface*)src)->m_bitmap, srcRect, dstRect, &paint, @@ -401,7 +402,7 @@ public: SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h)); SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + paint.setBlendMode(SkBlendMode::kSrcOver); m_canvas->drawBitmapRect( ((SkiaSurface*)src)->m_bitmap, srcRect, dstRect, &paint, @@ -417,7 +418,7 @@ public: SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(clip.dst.x, clip.dst.y, clip.size.w, clip.size.h)); SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + paint.setBlendMode(SkBlendMode::kSrcOver); if (gfx::geta(bg) > 0) { SkPaint paint; @@ -447,6 +448,8 @@ public: rebuild(); } + static Surface* loadSurface(const char* filename); + private: void rebuild() { ASSERT(!m_surface); @@ -456,12 +459,16 @@ private: m_clip = gfx::Rect(0, 0, width(), height()); } + static sk_sp colorSpace(); + SkBitmap m_bitmap; sk_sp m_surface; SkCanvas* m_canvas; SkPaint m_paint; gfx::Rect m_clip; int m_lock; + static sk_sp m_colorSpace; + }; } // namespace she diff --git a/src/she/skia/skia_system.h b/src/she/skia/skia_system.h index c978bd121..adddf5abb 100644 --- a/src/she/skia/skia_system.h +++ b/src/she/skia/skia_system.h @@ -9,11 +9,6 @@ #pragma once #include "base/base.h" -#include "base/file_handle.h" - -#include "SkCodec.h" -#include "SkPixelRef.h" -#include "SkStream.h" #include "she/common/system.h" #include "she/skia/skia_display.h" @@ -32,6 +27,8 @@ #define SkiaSystemBase CommonSystem #endif +#include "SkGraphics.h" + namespace she { EventQueueImpl g_queue; @@ -41,9 +38,11 @@ public: SkiaSystem() : m_defaultDisplay(nullptr) , m_gpuAcceleration(false) { + SkGraphics::Init(); } ~SkiaSystem() { + SkGraphics::Term(); } void dispose() override { @@ -129,28 +128,7 @@ public: } Surface* loadSurface(const char* filename) override { - base::FileHandle fp(base::open_file_with_exception(filename, "rb")); - - SkAutoTDelete codec( - SkCodec::NewFromStream( - new SkFILEStream(fp.get(), SkFILEStream::kCallerRetains_Ownership))); - if (!codec) - return nullptr; - - SkImageInfo info = codec->getInfo() - .makeColorType(kN32_SkColorType) - .makeAlphaType(kPremul_SkAlphaType); - SkBitmap bm; - if (!bm.tryAllocPixels(info)) - return nullptr; - - const SkCodec::Result r = codec->getPixels(info, bm.getPixels(), bm.rowBytes()); - if (r != SkCodec::kSuccess) - return nullptr; - - SkiaSurface* sur = new SkiaSurface(); - sur->swapBitmap(bm); - return sur; + return SkiaSurface::loadSurface(filename); } Surface* loadRgbaSurface(const char* filename) override { diff --git a/src/she/skia/skia_window_osx.mm b/src/she/skia/skia_window_osx.mm index d046efb6c..85b6c9093 100644 --- a/src/she/skia/skia_window_osx.mm +++ b/src/she/skia/skia_window_osx.mm @@ -10,6 +10,7 @@ #include "she/skia/skia_window_osx.h" +#include "base/log.h" #include "base/unique_ptr.h" #include "gfx/size.h" #include "she/event.h" @@ -30,6 +31,8 @@ #endif +#include + namespace she { class SkiaWindow::Impl : public OSXWindowImpl { @@ -196,7 +199,7 @@ private: m_glInterfaces.reset(GrGLCreateNativeInterface()); if (!m_glInterfaces || !m_glInterfaces->validate()) { - LOG("Cannot create GL interfaces\n"); + LOG(ERROR) << "OS: Cannot create GL interfaces\n"; detachGL(); return false; } @@ -209,10 +212,10 @@ private: initWithCGLContextObj:static_cast(m_glCtx.get())->cglContext()]; [m_nsGL setView:m_window.contentView]; - LOG("Using CGL backend\n"); + LOG("OS: Using CGL backend\n"); } catch (const std::exception& ex) { - LOG("Cannot create GL context: %s\n", ex.what()); + LOG(ERROR) << "OS: Cannot create GL context: " << ex.what() << "\n"; detachGL(); return false; } @@ -226,7 +229,6 @@ private: m_skSurface.reset(nullptr); m_skSurfaceDirect.reset(nullptr); - m_grRenderTarget.reset(nullptr); m_grCtx.reset(nullptr); m_glCtx.reset(nullptr); } @@ -243,11 +245,10 @@ private: desc.fSampleCnt = m_glCtx->getSampleCount(); desc.fStencilBits = m_glCtx->getStencilBits(); desc.fRenderTargetHandle = 0; // direct frame buffer - m_grRenderTarget.reset(m_grCtx->textureProvider()->wrapBackendRenderTarget(desc)); m_skSurface.reset(nullptr); // set m_skSurface comparing with the old m_skSurfaceDirect - m_skSurfaceDirect = - SkSurface::MakeRenderTargetDirect(m_grRenderTarget.get()); + m_skSurfaceDirect = SkSurface::MakeFromBackendRenderTarget( + m_grCtx.get(), desc, nullptr); if (scale == 1) { m_skSurface = m_skSurfaceDirect; @@ -327,7 +328,6 @@ private: SkAutoTUnref m_glInterfaces; NSOpenGLContext* m_nsGL; sk_sp m_grCtx; - sk_sp m_grRenderTarget; sk_sp m_skSurfaceDirect; sk_sp m_skSurface; gfx::Size m_lastSize; diff --git a/src/she/skia/skia_window_win.cpp b/src/she/skia/skia_window_win.cpp index 169503ca7..5d3b2f58e 100644 --- a/src/she/skia/skia_window_win.cpp +++ b/src/she/skia/skia_window_win.cpp @@ -33,6 +33,7 @@ #endif +#include namespace she { @@ -214,10 +215,10 @@ bool SkiaWindow::attachANGLE() GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)m_glInterfaces.get())); - LOG("Using EGL backend\n"); + LOG("OS: Using EGL backend\n"); } catch (const std::exception& ex) { - LOG("Error initializing EGL backend: %s\n", ex.what()); + LOG(ERROR) << "OS: Error initializing EGL backend: " << ex.what() << "\n"; detachGL(); } } @@ -250,10 +251,10 @@ bool SkiaWindow::attachGL() GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)m_glInterfaces.get())); - LOG("Using WGL backend\n"); + LOG("OS: Using WGL backend\n"); } catch (const std::exception& ex) { - LOG("Error initializing WGL backend: %s\n", ex.what()); + LOG(ERROR) << "OS: Error initializing WGL backend: " << ex.what() << "\n"; detachGL(); } } @@ -271,7 +272,6 @@ void SkiaWindow::detachGL() m_skSurface.reset(nullptr); m_skSurfaceDirect.reset(nullptr); - m_grRenderTarget.reset(nullptr); m_grCtx.reset(nullptr); m_glCtx.reset(nullptr); } @@ -289,11 +289,10 @@ void SkiaWindow::createRenderTarget(const gfx::Size& size) desc.fSampleCnt = m_sampleCount; desc.fStencilBits = m_stencilBits; desc.fRenderTargetHandle = 0; // direct frame buffer - m_grRenderTarget.reset(m_grCtx->textureProvider()->wrapBackendRenderTarget(desc)); m_skSurface.reset(nullptr); // set m_skSurface comparing with the old m_skSurfaceDirect - m_skSurfaceDirect = - SkSurface::MakeRenderTargetDirect(m_grRenderTarget.get()); + m_skSurfaceDirect = SkSurface::MakeFromBackendRenderTarget( + m_grCtx.get(), desc, nullptr); if (scale == 1) { m_skSurface = m_skSurfaceDirect; diff --git a/src/she/skia/skia_window_win.h b/src/she/skia/skia_window_win.h index f7e821310..75ef0eec5 100644 --- a/src/she/skia/skia_window_win.h +++ b/src/she/skia/skia_window_win.h @@ -54,7 +54,6 @@ private: base::UniquePtr m_glCtx; SkAutoTUnref m_glInterfaces; sk_sp m_grCtx; - sk_sp m_grRenderTarget; sk_sp m_skSurfaceDirect; sk_sp m_skSurface; int m_sampleCount; diff --git a/src/she/win/pen.cpp b/src/she/win/pen.cpp index f76d50da8..8f7ce5ae5 100644 --- a/src/she/win/pen.cpp +++ b/src/she/win/pen.cpp @@ -16,6 +16,8 @@ #include "base/path.h" #include "base/string.h" +#include + typedef UINT (API* WTInfoW_Func)(UINT, UINT, LPVOID); typedef HCTX (API* WTOpenW_Func)(HWND, LPLOGCONTEXTW, BOOL); typedef BOOL (API* WTClose_Func)(HCTX); @@ -57,11 +59,10 @@ HCTX PenAPI::open(HWND hwnd) ASSERT(logctx.lcOptions & CXO_SYSTEM); if (infoRes != sizeof(LOGCONTEXTW)) { - LOG("Not supported WTInfo:\n" - " Expected context size: %d\n" - " Actual context size: %d (options %d)\n", - sizeof(LOGCONTEXTW), - infoRes, logctx.lcOptions); + LOG(ERROR) + << "PEN: Not supported WTInfo:\n" + << " Expected context size: " << sizeof(LOGCONTEXTW) << "\n" + << " Actual context size: " << infoRes << " (options " << logctx.lcOptions << ")\n"; return nullptr; } @@ -75,11 +76,11 @@ HCTX PenAPI::open(HWND hwnd) HCTX ctx = WTOpen(hwnd, &logctx, TRUE); if (!ctx) { - LOG("Error attaching pen to display\n"); + LOG("PEN: Error attaching pen to display\n"); return nullptr; } - LOG("Pen attached to display\n"); + LOG("PEN: Pen attached to display\n"); return ctx; } @@ -87,7 +88,7 @@ void PenAPI::close(HCTX ctx) { if (ctx) { ASSERT(m_wintabLib); - LOG("Pen detached from window\n"); + LOG("PEN: Pen detached from window\n"); WTClose(ctx); } } @@ -103,7 +104,7 @@ bool PenAPI::loadWintab() m_wintabLib = base::load_dll("wintab32.dll"); if (!m_wintabLib) { - LOG("wintab32.dll is not present\n"); + LOG(ERROR) << "PEN: wintab32.dll is not present\n"; return false; } @@ -112,11 +113,11 @@ bool PenAPI::loadWintab() WTClose = base::get_dll_proc(m_wintabLib, "WTClose"); WTPacket = base::get_dll_proc(m_wintabLib, "WTPacket"); if (!WTInfo || !WTOpen || !WTClose || !WTPacket) { - LOG("wintab32.dll does not contain all required functions\n"); + LOG(ERROR) << "PEN: wintab32.dll does not contain all required functions\n"; return false; } - LOG("Pen initialized\n"); + LOG("PEN: Pen initialized\n"); return true; } diff --git a/src/steam/steam.cpp b/src/steam/steam.cpp index 29d8cd821..7c7041539 100644 --- a/src/steam/steam.cpp +++ b/src/steam/steam.cpp @@ -40,22 +40,22 @@ public: base::join_path(base::get_file_path(base::get_app_path()), STEAM_API_DLL_FILENAME)); if (!m_steamLib) { - LOG("Steam library not found...\n"); + LOG("STEAM: Steam library not found...\n"); return; } auto SteamAPI_Init = base::get_dll_proc(m_steamLib, "SteamAPI_Init"); if (!SteamAPI_Init) { - LOG("SteamAPI_Init not found...\n"); + LOG("STEAM: SteamAPI_Init not found...\n"); return; } if (!SteamAPI_Init()) { - LOG("Steam is not initialized...\n"); + LOG("STEAM: Steam is not initialized...\n"); return; } - LOG("Steam initialized...\n"); + LOG("STEAM: Steam initialized...\n"); m_initialized = true; } @@ -65,7 +65,7 @@ public: auto SteamAPI_Shutdown = base::get_dll_proc(m_steamLib, "SteamAPI_Shutdown"); if (SteamAPI_Shutdown) { - LOG("Steam shutdown...\n"); + LOG("STEAM: Steam shutdown...\n"); SteamAPI_Shutdown(); } diff --git a/src/ui/theme.cpp b/src/ui/theme.cpp index b65369ab4..3125180f0 100644 --- a/src/ui/theme.cpp +++ b/src/ui/theme.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2001-2013, 2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -58,10 +58,15 @@ void Theme::regenerate() void CurrentTheme::set(Theme* theme) { - current_theme = theme; + if (theme) { + // As the regeneration may fail, first we regenerate the theme and + // then we set is as "the current theme." E.g. In case that we'd + // like to show some kind of error message with the UI controls, + // we should be able to use the previous theme to do so (instead + // of this new unsuccessfully regenerated theme). + theme->regenerate(); - if (current_theme) { - current_theme->regenerate(); + current_theme = theme; Manager* manager = Manager::getDefault(); if (manager && !manager->theme()) diff --git a/src/ui/widget.cpp b/src/ui/widget.cpp index 56946271d..c88d4567c 100644 --- a/src/ui/widget.cpp +++ b/src/ui/widget.cpp @@ -160,10 +160,8 @@ void Widget::setTextQuiet(const std::string& text) she::Font* Widget::font() const { - if (!m_font) { - ASSERT(m_theme); + if (!m_font && m_theme) m_font = m_theme->getWidgetFont(this); - } return m_font; } diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index dc6c5cce7..3f08bdfcd 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -31,7 +31,10 @@ endif() if(WITH_WEBP_SUPPORT) if(NOT USE_SHARED_LIBWEBP) - add_subdirectory(libwebp-cmake) + # Skia already includes webp library + if(NOT USE_SKIA_BACKEND) + add_subdirectory(libwebp-cmake) + endif() endif() endif() diff --git a/third_party/libwebp b/third_party/libwebp index 03fb75221..31b1e3434 160000 --- a/third_party/libwebp +++ b/third_party/libwebp @@ -1 +1 @@ -Subproject commit 03fb75221c36ff773379eb5f018d7206f1ef30c9 +Subproject commit 31b1e3434227c9614e441adf017baf6002d686ab