From 4584d67b69029f4d362d33f02a325e0ec6c155ad Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 5 Mar 2024 19:39:50 -0300 Subject: [PATCH 1/6] Update modules --- laf | 2 +- src/clip | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/laf b/laf index 3be4aa115..6d19cc2e8 160000 --- a/laf +++ b/laf @@ -1 +1 @@ -Subproject commit 3be4aa115bfc7a009a49a57a09c4b7dd509ebfcd +Subproject commit 6d19cc2e890576b07399e3d157da83d04acbc99b diff --git a/src/clip b/src/clip index 94693e241..835cd0f7e 160000 --- a/src/clip +++ b/src/clip @@ -1 +1 @@ -Subproject commit 94693e2414a2c69a8ca16f065240c80a94cc6221 +Subproject commit 835cd0f7e7a964bb969482117856bc56a0ac12bf From 50d4f9d8028dc56686b7f0720ef4775db7b2f782 Mon Sep 17 00:00:00 2001 From: David Capello Date: Wed, 6 Mar 2024 09:59:20 -0300 Subject: [PATCH 2/6] Don't try to clone strings repo if Git isn't available (fix #4357) This can happen when the source code is downloaded as a .zip and the Git command is not available to clone the strings repo. --- src/CMakeLists.txt | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 708dc7c6d..b44d245bf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -157,17 +157,22 @@ set(DATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin/data) include(FetchContent) -FetchContent_Declare( - clone_strings - GIT_REPOSITORY https://github.com/aseprite/strings.git - GIT_TAG origin/main - SOURCE_DIR ${DATA_OUTPUT_DIR}/strings.git - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "") -FetchContent_MakeAvailable(clone_strings) -add_custom_target(clone_strings DEPENDS clone_strings) +find_package(Git) +if(GIT_FOUND) + FetchContent_Declare( + clone_strings + GIT_REPOSITORY https://github.com/aseprite/strings.git + GIT_TAG origin/main + SOURCE_DIR ${DATA_OUTPUT_DIR}/strings.git + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "") + FetchContent_MakeAvailable(clone_strings) + add_custom_target(clone_strings DEPENDS clone_strings) +else() + add_custom_target(clone_strings) +endif() ###################################################################### # Copy data/ directory target into bin/data/ @@ -182,14 +187,16 @@ foreach(fn ${src_data_files}) list(APPEND out_data_files ${DATA_OUTPUT_DIR}/${fn}) endforeach() -# Copy original en.ini to strings.git/en.ini to keep it updated. We -# have to manually sync the "en.ini" file in the "strings" repo from -# the "aseprite" repo. -add_custom_command( - OUTPUT ${DATA_OUTPUT_DIR}/strings.git/en.ini - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SOURCE_DATA_DIR}/strings/en.ini ${DATA_OUTPUT_DIR}/strings.git/en.ini - MAIN_DEPENDENCY ${SOURCE_DATA_DIR}/strings/en.ini) -list(APPEND out_data_files ${DATA_OUTPUT_DIR}/strings.git/en.ini) +if(GIT_FOUND) + # Copy original en.ini to strings.git/en.ini to keep it updated. We + # have to manually sync the "en.ini" file in the "strings" repo from + # the "aseprite" repo. + add_custom_command( + OUTPUT ${DATA_OUTPUT_DIR}/strings.git/en.ini + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SOURCE_DATA_DIR}/strings/en.ini ${DATA_OUTPUT_DIR}/strings.git/en.ini + MAIN_DEPENDENCY ${SOURCE_DATA_DIR}/strings/en.ini) + list(APPEND out_data_files ${DATA_OUTPUT_DIR}/strings.git/en.ini) +endif() add_custom_command( OUTPUT ${DATA_OUTPUT_DIR}/README.md From b8514ad1c656ec429cd5b1c42224170c6dab392d Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 11 Mar 2024 10:34:05 -0300 Subject: [PATCH 3/6] Add helper functions make_shader(), make_skimage/skcanvas_for_docimage() These functions can be used to create a new Skia shader from SkSL code, and a new SkImage/SkCanvas to modify a doc::Image* --- src/app/CMakeLists.txt | 1 + src/app/render/shader_renderer.cpp | 48 ++------------- src/app/util/shader_helpers.cpp | 94 ++++++++++++++++++++++++++++++ src/app/util/shader_helpers.h | 32 ++++++++-- 4 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 src/app/util/shader_helpers.cpp diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 979ea91b7..4fdaceeb8 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -699,6 +699,7 @@ add_library(app-lib util/range_utils.cpp util/readable_time.cpp util/resize_image.cpp + util/shader_helpers.cpp util/tile_flags_utils.cpp util/tileset_utils.cpp util/wrap_point.cpp diff --git a/src/app/render/shader_renderer.cpp b/src/app/render/shader_renderer.cpp index 832f9a335..42b868b6b 100644 --- a/src/app/render/shader_renderer.cpp +++ b/src/app/render/shader_renderer.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2022-2023 Igara Studio S.A. +// Copyright (C) 2022-2024 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -87,19 +87,9 @@ ShaderRenderer::ShaderRenderer() m_properties.renderBgOnScreen = true; m_properties.requiresRgbaBackbuffer = true; - auto makeShader = [](const char* code) { - auto result = SkRuntimeEffect::MakeForShader(SkString(code)); - if (!result.errorText.isEmpty()) { - LOG(ERROR, "Shader error: %s\n", result.errorText.c_str()); - std::printf("Shader error: %s\n", result.errorText.c_str()); - throw std::runtime_error("Cannot compile shaders for ShaderRenderer"); - } - return result; - }; - - m_bgEffect = makeShader(kBgShaderCode).effect; - m_indexedEffect = makeShader(kIndexedShaderCode).effect; - m_grayscaleEffect = makeShader(kGrayscaleShaderCode).effect; + m_bgEffect = make_shader(kBgShaderCode); + m_indexedEffect = make_shader(kIndexedShaderCode); + m_grayscaleEffect = make_shader(kGrayscaleShaderCode); } ShaderRenderer::~ShaderRenderer() = default; @@ -416,21 +406,11 @@ void ShaderRenderer::drawImage(SkCanvas* canvas, const int opacity, const doc::BlendMode blendMode) { - auto skData = SkData::MakeWithoutCopy( - (const void*)srcImage->getPixelAddress(0, 0), - srcImage->rowBytes() * srcImage->height()); + auto skImg = make_skimage_for_docimage(srcImage); switch (srcImage->colorMode()) { case doc::ColorMode::RGB: { - auto skImg = SkImage::MakeRasterData( - SkImageInfo::Make(srcImage->width(), - srcImage->height(), - kRGBA_8888_SkColorType, - kUnpremul_SkAlphaType), - skData, - srcImage->rowBytes()); - SkPaint p; p.setAlpha(opacity); p.setBlendMode(to_skia(blendMode)); @@ -443,15 +423,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas, } case doc::ColorMode::GRAYSCALE: { - // We use kR8G8_unorm_SkColorType to access gray and alpha - auto skImg = SkImage::MakeRasterData( - SkImageInfo::Make(srcImage->width(), - srcImage->height(), - kR8G8_unorm_SkColorType, - kOpaque_SkAlphaType), - skData, - srcImage->rowBytes()); - SkRuntimeShaderBuilder builder(m_grayscaleEffect); builder.child("iImg") = skImg->makeRawShader(SkSamplingOptions(SkFilterMode::kNearest)); @@ -471,15 +442,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas, } case doc::ColorMode::INDEXED: { - // We use kAlpha_8_SkColorType to access to the index value through the alpha channel - auto skImg = SkImage::MakeRasterData( - SkImageInfo::Make(srcImage->width(), - srcImage->height(), - kAlpha_8_SkColorType, - kUnpremul_SkAlphaType), - skData, - srcImage->rowBytes()); - // Use the palette data as an "width x height" image where // width=number of palette colors, and height=1 const size_t palSize = sizeof(color_t) * m_palette.size(); diff --git a/src/app/util/shader_helpers.cpp b/src/app/util/shader_helpers.cpp new file mode 100644 index 000000000..c465a286b --- /dev/null +++ b/src/app/util/shader_helpers.cpp @@ -0,0 +1,94 @@ +// Aseprite +// Copyright (C) 2024 Igara Studio S.A. +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if SK_ENABLE_SKSL + +#include "app/util/shader_helpers.h" + +#include "base/exception.h" +#include "doc/image.h" +#include "fmt/format.h" + +#include "include/effects/SkRuntimeEffect.h" + +namespace app { + +sk_sp make_shader(const char* code) +{ + auto result = SkRuntimeEffect::MakeForShader(SkString(code)); + if (!result.errorText.isEmpty()) { + std::string error = fmt::format("Error compiling shader.\nError: {}\n", + result.errorText.c_str()); + LOG(ERROR, error.c_str()); + std::printf("%s", error.c_str()); + throw base::Exception(error); + } + return result.effect; +} + +SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img) +{ + switch (img->colorMode()) { + + case doc::ColorMode::RGB: + return SkImageInfo::Make(img->width(), + img->height(), + kRGBA_8888_SkColorType, + kUnpremul_SkAlphaType); + + case doc::ColorMode::GRAYSCALE: + // We use kR8G8_unorm_SkColorType to access gray and alpha + return SkImageInfo::Make(img->width(), + img->height(), + kR8G8_unorm_SkColorType, + kOpaque_SkAlphaType); + + case doc::ColorMode::INDEXED: { + // We use kAlpha_8_SkColorType to access to the index value through the alpha channel + return SkImageInfo::Make(img->width(), + img->height(), + kAlpha_8_SkColorType, + kUnpremul_SkAlphaType); + + } + } + return SkImageInfo(); +} + +sk_sp make_skimage_for_docimage(const doc::Image* img) +{ + switch (img->colorMode()) { + case doc::ColorMode::RGB: + case doc::ColorMode::GRAYSCALE: + case doc::ColorMode::INDEXED: { + auto skData = SkData::MakeWithoutCopy( + (const void*)img->getPixelAddress(0, 0), + img->rowBytes() * img->height()); + + return SkImage::MakeRasterData( + get_skimageinfo_for_docimage(img), + skData, + img->rowBytes()); + } + } + return nullptr; +} + +std::unique_ptr make_skcanvas_for_docimage(const doc::Image* img) +{ + return SkCanvas::MakeRasterDirect( + get_skimageinfo_for_docimage(img), + (void*)img->getPixelAddress(0, 0), + img->rowBytes()); +} + +} // namespace app + +#endif // SK_ENABLE_SKSL diff --git a/src/app/util/shader_helpers.h b/src/app/util/shader_helpers.h index b122b34d1..9ca463d0d 100644 --- a/src/app/util/shader_helpers.h +++ b/src/app/util/shader_helpers.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2022 Igara Studio S.A. +// Copyright (C) 2022-2024 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -8,18 +8,32 @@ #define APP_UTIL_SHADER_HELPERS_H_INCLUDED #pragma once -#if SK_ENABLE_SKSL +#if LAF_SKIA #include "app/color.h" #include "gfx/color.h" +#include "include/core/SkCanvas.h" +#include "include/core/SkImage.h" #include "include/core/SkM44.h" +#include "include/core/SkRefCnt.h" -// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl -#include "src/core/SkRuntimeEffectPriv.h" +#if SK_ENABLE_SKSL + #include "include/effects/SkRuntimeEffect.h" + // To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl + #include "src/core/SkRuntimeEffectPriv.h" +#endif + +#include + +namespace doc { + class Image; +} namespace app { +#if SK_ENABLE_SKSL + // rgb_to_hsl() and hsv_to_hsl() functions by Sam Hocevar licensed // under WTFPL (https://en.wikipedia.org/wiki/WTFPL) // Source: @@ -74,8 +88,16 @@ inline SkV4 appColorHsl_to_SkV4(const app::Color& color) { float(color.getAlpha() / 255.0)}; } +sk_sp make_shader(const char* code); + +#endif // SK_ENABLE_SKSL + +SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img); +sk_sp make_skimage_for_docimage(const doc::Image* img); +std::unique_ptr make_skcanvas_for_docimage(const doc::Image* img); + } // namespace app -#endif +#endif // LAF_SKIA #endif From 7f659d2f86fc7d36b1506049a3c414511e57dc50 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 11 Mar 2024 11:06:57 -0300 Subject: [PATCH 4/6] Handle exceptions that DocDestroyer can throw (probably #4367) --- src/app/commands/cmd_export_sprite_sheet.cpp | 32 ++++++++++++-------- src/app/commands/cmd_import_sprite_sheet.cpp | 12 ++++++-- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index 5c5458f83..552c8e6a0 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019-2022 Igara Studio S.A. +// Copyright (C) 2019-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -11,6 +11,7 @@ #include "app/app.h" #include "app/commands/cmd_export_sprite_sheet.h" +#include "app/console.h" #include "app/context.h" #include "app/context_access.h" #include "app/doc.h" @@ -141,6 +142,17 @@ ConstraintType constraint_type_from_params(const ExportSpriteSheetParams& params #endif // ENABLE_UI +void destroy_doc(Context* ctx, Doc* doc) +{ + try { + DocDestroyer destroyer(ctx, doc, 500); + destroyer.destroyDocument(); + } + catch (const LockedDocException& ex) { + Console::showException(ex); + } +} + Doc* generate_sprite_sheet_from_params( DocExporter& exporter, Context* ctx, @@ -500,8 +512,7 @@ public: auto ctx = UIContext::instance(); ctx->setActiveDocument(m_site.document()); - DocDestroyer destroyer(ctx, m_spriteSheet.release(), 100); - destroyer.destroyDocument(); + destroy_doc(ctx, m_spriteSheet.release()); } } @@ -1014,8 +1025,7 @@ private: auto ctx = UIContext::instance(); ctx->setActiveDocument(m_site.document()); - DocDestroyer destroyer(ctx, m_spriteSheet.release(), 100); - destroyer.destroyDocument(); + destroy_doc(ctx, m_spriteSheet.release()); m_editor = nullptr; } return; @@ -1066,8 +1076,7 @@ private: return; if (token.canceled()) { - DocDestroyer destroyer(&tmpCtx, newDocument, 100); - destroyer.destroyDocument(); + destroy_doc(&tmpCtx, newDocument); return; } @@ -1090,8 +1099,7 @@ private: // old one. IN this case the newDocument contains a back // buffer (ImageBufferPtr) that will be discarded. m_executionID != executionID) { - DocDestroyer destroyer(context, newDocument, 100); - destroyer.destroyDocument(); + destroy_doc(context, newDocument); return; } @@ -1137,8 +1145,7 @@ private: m_spriteSheet->notifyGeneralUpdate(); - DocDestroyer destroyer(context, newDocument, 100); - destroyer.destroyDocument(); + destroy_doc(context, newDocument); } waitGenTaskAndDelete(); @@ -1407,8 +1414,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context) newDocument.release(); } else { - DocDestroyer destroyer(context, newDocument.release(), 100); - destroyer.destroyDocument(); + destroy_doc(context, newDocument.release()); } } diff --git a/src/app/commands/cmd_import_sprite_sheet.cpp b/src/app/commands/cmd_import_sprite_sheet.cpp index 0ba752077..955ea442e 100644 --- a/src/app/commands/cmd_import_sprite_sheet.cpp +++ b/src/app/commands/cmd_import_sprite_sheet.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019-2022 Igara Studio S.A. +// Copyright (C) 2019-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -13,6 +13,7 @@ #include "app/commands/command.h" #include "app/commands/commands.h" #include "app/commands/new_params.h" +#include "app/console.h" #include "app/context.h" #include "app/context_access.h" #include "app/doc_access.h" @@ -264,8 +265,13 @@ private: releaseEditor(); if (m_fileOpened) { - DocDestroyer destroyer(m_context, oldDocument, 100); - destroyer.destroyDocument(); + try { + DocDestroyer destroyer(m_context, oldDocument, 500); + destroyer.destroyDocument(); + } + catch (const LockedDocException& ex) { + Console::showException(ex); + } } } From 7905acf38a8114c13270bed61305851642454e31 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 11 Mar 2024 17:15:13 -0300 Subject: [PATCH 5/6] Handle some extra CannotWriteDocException cases when ContextWriter is used (#4367) One fix that this patch includes for #4367 (crash by unhandled CannotWriteDocException exception) is when we drag-and-drop a tag border to resize its limits. This is a fix for that case but we don't know if this include all cases of #4367 crashes (so we cannot close the issue). Anyway we have added some try { } catch in cases where it's better to avoid propagating the exception, e.g. in MovingSelectionState::onLeaveState() to avoid throwing exceptions in Editor::backToPreviousState() which might be problematic in several cases. (Maybe related to #2829?) --- src/app/commands/cmd_mask_by_color.cpp | 20 ++++----- src/app/commands/cmd_options.cpp | 13 ++++-- src/app/commands/cmd_sprite_properties.cpp | 45 ++++++++++++-------- src/app/ui/editor/moving_selection_state.cpp | 8 +++- src/app/ui/input_chain_element.h | 3 ++ src/app/ui/timeline/timeline.cpp | 27 +++++++----- 6 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/app/commands/cmd_mask_by_color.cpp b/src/app/commands/cmd_mask_by_color.cpp index 18fa656b3..71d6fad04 100644 --- a/src/app/commands/cmd_mask_by_color.cpp +++ b/src/app/commands/cmd_mask_by_color.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2023 Igara Studio S.A. +// Copyright (C) 2018-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -14,11 +14,12 @@ #include "app/color.h" #include "app/color_utils.h" #include "app/commands/command.h" +#include "app/console.h" #include "app/context.h" #include "app/context_access.h" #include "app/doc.h" -#include "app/ini_file.h" #include "app/i18n/strings.h" +#include "app/ini_file.h" #include "app/modules/gui.h" #include "app/tx.h" #include "app/ui/color_bar.h" @@ -260,22 +261,21 @@ void MaskByColorCommand::maskPreview(const ContextReader& reader) reader.sprite(), image, xpos, ypos, m_selMode->selectionMode())); - { - ContextWriter writer(reader); + + ContextWriter writer(reader); #ifdef SHOW_BOUNDARIES_GEN_PERFORMANCE - base::Chrono chrono; + base::Chrono chrono; #endif - writer.document()->generateMaskBoundaries(mask.get()); + writer.document()->generateMaskBoundaries(mask.get()); #ifdef SHOW_BOUNDARIES_GEN_PERFORMANCE - double time = chrono.elapsed(); - m_window->setText("Mask by Color (" + base::convert_to(time) + ")"); + double time = chrono.elapsed(); + m_window->setText("Mask by Color (" + base::convert_to(time) + ")"); #endif - update_screen_for_document(writer.document()); - } + update_screen_for_document(writer.document()); } } diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp index 19ea43383..63f9d89fa 100644 --- a/src/app/commands/cmd_options.cpp +++ b/src/app/commands/cmd_options.cpp @@ -784,10 +784,15 @@ public: m_context->activeDocument() && m_context->activeDocument()->sprite() && m_context->activeDocument()->sprite()->gridBounds() != gridBounds()) { - ContextWriter writer(m_context); - Tx tx(writer, Strings::commands_GridSettings(), ModifyDocument); - tx(new cmd::SetGridBounds(writer.sprite(), gridBounds())); - tx.commit(); + try { + ContextWriter writer(m_context, 1000); + Tx tx(writer, Strings::commands_GridSettings(), ModifyDocument); + tx(new cmd::SetGridBounds(writer.sprite(), gridBounds())); + tx.commit(); + } + catch (const std::exception& ex) { + Console::showException(ex); + } } m_curPref->show.grid(gridVisible()->isSelected()); diff --git a/src/app/commands/cmd_sprite_properties.cpp b/src/app/commands/cmd_sprite_properties.cpp index 14327fb98..a601b6fb4 100644 --- a/src/app/commands/cmd_sprite_properties.cpp +++ b/src/app/commands/cmd_sprite_properties.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2023 Igara Studio S.A. +// Copyright (C) 2018-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -9,31 +9,32 @@ #include "config.h" #endif +#include "app/cmd/add_tileset.h" #include "app/cmd/assign_color_profile.h" #include "app/cmd/convert_color_profile.h" -#include "app/cmd/add_tileset.h" #include "app/cmd/remove_tileset.h" #include "app/cmd/set_pixel_ratio.h" #include "app/cmd/set_user_data.h" #include "app/color.h" #include "app/commands/command.h" +#include "app/console.h" #include "app/context_access.h" #include "app/doc_api.h" #include "app/i18n/strings.h" #include "app/modules/gui.h" #include "app/pref/preferences.h" -#include "app/util/tileset_utils.h" #include "app/tx.h" #include "app/ui/color_button.h" -#include "app/ui/user_data_view.h" #include "app/ui/skin/skin_theme.h" +#include "app/ui/user_data_view.h" #include "app/util/pixel_ratio.h" +#include "app/util/tileset_utils.h" #include "base/mem_utils.h" #include "doc/image.h" #include "doc/palette.h" #include "doc/sprite.h" -#include "doc/user_data.h" #include "doc/tilesets.h" +#include "doc/user_data.h" #include "fmt/format.h" #include "os/color_space.h" #include "os/system.h" @@ -351,12 +352,17 @@ void SpritePropertiesCommand::onExecute(Context* context) [&](){ selectedColorProfile = window.colorProfile()->getSelectedItemIndex(); - ContextWriter writer(context); - Sprite* sprite(writer.sprite()); - Tx tx(writer, Strings::sprite_properties_assign_color_profile()); - tx(new cmd::AssignColorProfile( - sprite, colorSpaces[selectedColorProfile]->gfxColorSpace())); - tx.commit(); + try { + ContextWriter writer(context); + Sprite* sprite(writer.sprite()); + Tx tx(writer, Strings::sprite_properties_assign_color_profile()); + tx(new cmd::AssignColorProfile( + sprite, colorSpaces[selectedColorProfile]->gfxColorSpace())); + tx.commit(); + } + catch (const base::Exception& e) { + Console::showException(e); + } updateButtons(); }); @@ -364,12 +370,17 @@ void SpritePropertiesCommand::onExecute(Context* context) [&](){ selectedColorProfile = window.colorProfile()->getSelectedItemIndex(); - ContextWriter writer(context); - Sprite* sprite(writer.sprite()); - Tx tx(writer, Strings::sprite_properties_convert_color_profile()); - tx(new cmd::ConvertColorProfile( - sprite, colorSpaces[selectedColorProfile]->gfxColorSpace())); - tx.commit(); + try { + ContextWriter writer(context); + Sprite* sprite(writer.sprite()); + Tx tx(writer, Strings::sprite_properties_convert_color_profile()); + tx(new cmd::ConvertColorProfile( + sprite, colorSpaces[selectedColorProfile]->gfxColorSpace())); + tx.commit(); + } + catch (const base::Exception& e) { + Console::showException(e); + } updateButtons(); }); diff --git a/src/app/ui/editor/moving_selection_state.cpp b/src/app/ui/editor/moving_selection_state.cpp index 56bc0b77e..ef829a56f 100644 --- a/src/app/ui/editor/moving_selection_state.cpp +++ b/src/app/ui/editor/moving_selection_state.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019-2022 Igara Studio S.A. +// Copyright (C) 2019-2024 Igara Studio S.A. // Copyright (C) 2017-2018 David Capello // // This program is distributed under the terms of @@ -14,6 +14,7 @@ #include "app/cmd/set_mask_position.h" #include "app/commands/command.h" #include "app/commands/commands.h" +#include "app/console.h" #include "app/context_access.h" #include "app/tx.h" #include "app/ui/editor/editor.h" @@ -80,12 +81,15 @@ EditorState::LeaveAction MovingSelectionState::onLeaveState(Editor* editor, Edit doc->generateMaskBoundaries(); } else { - { + try { ContextWriter writer(UIContext::instance(), 1000); Tx tx(writer, "Move Selection Edges", DoesntModifyDocument); tx(new cmd::SetMaskPosition(doc, newOrigin)); tx.commit(); } + catch (const base::Exception& e) { + Console::showException(e); + } doc->resetTransformation(); } doc->notifyGeneralUpdate(); diff --git a/src/app/ui/input_chain_element.h b/src/app/ui/input_chain_element.h index 3a96135a5..17df4bec2 100644 --- a/src/app/ui/input_chain_element.h +++ b/src/app/ui/input_chain_element.h @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -29,6 +30,8 @@ namespace app { virtual bool onCanPaste(Context* ctx) = 0; virtual bool onCanClear(Context* ctx) = 0; + // These commands are executed from Context::executeCommand() + // which catch any exception that is thrown. virtual bool onCut(Context* ctx) = 0; virtual bool onCopy(Context* ctx) = 0; virtual bool onPaste(Context* ctx) = 0; diff --git a/src/app/ui/timeline/timeline.cpp b/src/app/ui/timeline/timeline.cpp index bf0b2f98c..b81f8f6da 100644 --- a/src/app/ui/timeline/timeline.cpp +++ b/src/app/ui/timeline/timeline.cpp @@ -1347,7 +1347,7 @@ bool Timeline::onProcessMessage(Message* msg) else if (mouseMsg->left()) { Command* command = Commands::instance() ->byId(CommandId::FrameTagProperties()); - UIContext::instance()->executeCommand(command, params); + m_context->executeCommand(command, params); } } break; @@ -1389,13 +1389,18 @@ bool Timeline::onProcessMessage(Message* msg) if (tag) { if ((m_state == STATE_RESIZING_TAG_LEFT && tag->fromFrame() != m_resizeTagData.from) || (m_state == STATE_RESIZING_TAG_RIGHT && tag->toFrame() != m_resizeTagData.to)) { - ContextWriter writer(UIContext::instance()); - Tx tx(writer, Strings::commands_FrameTagProperties()); - tx(new cmd::SetTagRange( - tag, - (m_state == STATE_RESIZING_TAG_LEFT ? m_resizeTagData.from: tag->fromFrame()), - (m_state == STATE_RESIZING_TAG_RIGHT ? m_resizeTagData.to: tag->toFrame()))); - tx.commit(); + try { + ContextWriter writer(m_context); + Tx tx(writer, Strings::commands_FrameTagProperties()); + tx(new cmd::SetTagRange( + tag, + (m_state == STATE_RESIZING_TAG_LEFT ? m_resizeTagData.from: tag->fromFrame()), + (m_state == STATE_RESIZING_TAG_RIGHT ? m_resizeTagData.to: tag->toFrame()))); + tx.commit(); + } + catch (const base::Exception& e) { + Console::showException(e); + } regenerateRows(); } @@ -1431,7 +1436,7 @@ bool Timeline::onProcessMessage(Message* msg) Command* command = Commands::instance() ->byId(CommandId::LayerProperties()); - UIContext::instance()->executeCommand(command); + m_context->executeCommand(command); return true; } @@ -1441,7 +1446,7 @@ bool Timeline::onProcessMessage(Message* msg) Params params; params.set("frame", "current"); - UIContext::instance()->executeCommand(command, params); + m_context->executeCommand(command, params); return true; } @@ -1449,7 +1454,7 @@ bool Timeline::onProcessMessage(Message* msg) Command* command = Commands::instance() ->byId(CommandId::CelProperties()); - UIContext::instance()->executeCommand(command); + m_context->executeCommand(command); return true; } From a0e469624a2b47d23c8a118ab92538fe9df2b727 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 11 Mar 2024 17:48:11 -0300 Subject: [PATCH 6/6] Use make_shader() helper function to create ColorSelector shaders --- src/app/ui/color_selector.cpp | 19 +++---------------- src/app/ui/color_selector.h | 1 - 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/app/ui/color_selector.cpp b/src/app/ui/color_selector.cpp index 53703c26f..b82b97e4e 100644 --- a/src/app/ui/color_selector.cpp +++ b/src/app/ui/color_selector.cpp @@ -655,35 +655,22 @@ bool ColorSelector::buildEffects() if (!m_mainEffect) { if (const char* code = getMainAreaShader()) - m_mainEffect = buildEffect(code); + m_mainEffect = make_shader(code); } if (!m_bottomEffect) { if (const char* code = getBottomBarShader()) - m_bottomEffect = buildEffect(code); + m_bottomEffect = make_shader(code); } if (!m_alphaEffect) { if (const char* code = getAlphaBarShader()) - m_alphaEffect = buildEffect(code); + m_alphaEffect = make_shader(code); } return (m_mainEffect && m_bottomEffect && m_alphaEffect); } -sk_sp ColorSelector::buildEffect(const char* code) -{ - auto result = SkRuntimeEffect::MakeForShader(SkString(code)); - if (!result.errorText.isEmpty()) { - LOG(ERROR, "Shader error: %s\n", result.errorText.c_str()); - std::printf("Shader error: %s\n", result.errorText.c_str()); - return nullptr; - } - else { - return result.effect; - } -} - void ColorSelector::resetBottomEffect() { m_bottomEffect.reset(); diff --git a/src/app/ui/color_selector.h b/src/app/ui/color_selector.h index 438cd591b..0d2047459 100644 --- a/src/app/ui/color_selector.h +++ b/src/app/ui/color_selector.h @@ -121,7 +121,6 @@ namespace app { #if SK_ENABLE_SKSL static const char* getAlphaBarShader(); bool buildEffects(); - sk_sp buildEffect(const char* code); #endif // Internal flag used to lock the modification of m_color.