mirror of https://github.com/aseprite/aseprite.git
Fix painting UI theme colors as they are specified in sRGB color space
Fixes a regression found after merging #5414: https://github.com/aseprite/aseprite/pull/5414#issuecomment-3286339563 We always expected a sRGB color in ui::Graphics API and we can specify a color in another color space using the ui::Paint version of its member functions. Several functions related to color spaces are now using a ui::Display to receive the specific display where we're going to paint, instead of using os::System::instance()->defaultWindow()->colorSpace().
This commit is contained in:
parent
5d5f3ec234
commit
c444b566e1
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include "app/ui/editor/editor.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
#include "ui/display.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -29,17 +30,15 @@ void initialize_color_spaces(Preferences& pref)
|
|||
pref.color.manage.AfterChange.connect([](bool manage) { g_manage = manage; });
|
||||
}
|
||||
|
||||
os::ColorSpaceRef get_screen_color_space()
|
||||
os::ColorSpaceRef get_current_color_space(ui::Display* display, Doc* doc)
|
||||
{
|
||||
return os::System::instance()->defaultWindow()->colorSpace();
|
||||
}
|
||||
|
||||
os::ColorSpaceRef get_current_color_space()
|
||||
{
|
||||
if (auto* editor = Editor::activeEditor())
|
||||
return editor->document()->osColorSpace();
|
||||
else
|
||||
return get_screen_color_space();
|
||||
if (!doc) {
|
||||
if (auto* editor = Editor::activeEditor())
|
||||
doc = editor->document();
|
||||
}
|
||||
if (doc)
|
||||
return doc->osColorSpace();
|
||||
return display->colorSpace();
|
||||
}
|
||||
|
||||
gfx::ColorSpaceRef get_working_rgb_space_from_preferences()
|
||||
|
@ -62,11 +61,11 @@ gfx::ColorSpaceRef get_working_rgb_space_from_preferences()
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Color conversion
|
||||
|
||||
ConvertCS::ConvertCS()
|
||||
ConvertCS::ConvertCS(ui::Display* display, Doc* doc)
|
||||
{
|
||||
if (g_manage) {
|
||||
auto srcCS = get_current_color_space();
|
||||
auto dstCS = get_screen_color_space();
|
||||
auto srcCS = get_current_color_space(display, doc);
|
||||
auto dstCS = display->colorSpace();
|
||||
if (srcCS && dstCS)
|
||||
m_conversion = os::System::instance()->convertBetweenColorSpace(srcCS, dstCS);
|
||||
}
|
||||
|
@ -95,9 +94,9 @@ gfx::Color ConvertCS::operator()(const gfx::Color c)
|
|||
}
|
||||
}
|
||||
|
||||
ConvertCS convert_from_current_to_screen_color_space()
|
||||
ConvertCS convert_from_current_to_display_color_space(ui::Display* display)
|
||||
{
|
||||
return ConvertCS();
|
||||
return ConvertCS(display);
|
||||
}
|
||||
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpaceRef& from)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2025 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -16,21 +16,25 @@ namespace doc {
|
|||
class Sprite;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class Display;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Doc;
|
||||
class Preferences;
|
||||
|
||||
void initialize_color_spaces(Preferences& pref);
|
||||
|
||||
os::ColorSpaceRef get_screen_color_space();
|
||||
|
||||
// Returns the color space of the current document.
|
||||
os::ColorSpaceRef get_current_color_space();
|
||||
os::ColorSpaceRef get_current_color_space(ui::Display* display, Doc* doc = nullptr);
|
||||
|
||||
gfx::ColorSpaceRef get_working_rgb_space_from_preferences();
|
||||
|
||||
class ConvertCS {
|
||||
public:
|
||||
ConvertCS();
|
||||
ConvertCS() = delete;
|
||||
ConvertCS(ui::Display* display, Doc* doc = nullptr);
|
||||
ConvertCS(const os::ColorSpaceRef& srcCS, const os::ColorSpaceRef& dstCS);
|
||||
ConvertCS(ConvertCS&&);
|
||||
ConvertCS& operator=(const ConvertCS&) = delete;
|
||||
|
@ -40,7 +44,7 @@ private:
|
|||
os::Ref<os::ColorSpaceConversion> m_conversion;
|
||||
};
|
||||
|
||||
ConvertCS convert_from_current_to_screen_color_space();
|
||||
ConvertCS convert_from_current_to_display_color_space(ui::Display* display);
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpaceRef& from);
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/paint.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
|
||||
|
@ -118,9 +119,6 @@ void draw_color(ui::Graphics* g,
|
|||
app::Color color = _color;
|
||||
const int alpha = color.getAlpha();
|
||||
|
||||
// Color space conversion
|
||||
auto convertColor = convert_from_current_to_screen_color_space();
|
||||
|
||||
if (alpha < 255) {
|
||||
if (rc.w == rc.h)
|
||||
draw_checkered_grid(g, rc, gfx::Size(rc.w / 2, rc.h / 2));
|
||||
|
@ -133,11 +131,15 @@ void draw_color(ui::Graphics* g,
|
|||
color = app::Color::fromGray(color.getGray(), color.getAlpha());
|
||||
}
|
||||
|
||||
// The color is in the current sprite color space.
|
||||
ui::Paint paint;
|
||||
paint.color(color_utils::color_for_ui(color), get_current_color_space(g->display()).get());
|
||||
|
||||
if (color.getType() == app::Color::IndexType) {
|
||||
int index = color.getIndex();
|
||||
|
||||
if (index >= 0 && index < get_current_palette()->size()) {
|
||||
g->fillRect(convertColor(color_utils::color_for_ui(color)), rc);
|
||||
g->drawRect(rc, paint);
|
||||
}
|
||||
else {
|
||||
g->fillRect(gfx::rgba(0, 0, 0), rc);
|
||||
|
@ -147,7 +149,7 @@ void draw_color(ui::Graphics* g,
|
|||
}
|
||||
}
|
||||
else {
|
||||
g->fillRect(convertColor(color_utils::color_for_ui(color)), rc);
|
||||
g->drawRect(rc, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +221,8 @@ void draw_tile(ui::Graphics* g, const Rect& rc, const Site& site, doc::tile_t ti
|
|||
int w = tileImage->width();
|
||||
int h = tileImage->height();
|
||||
|
||||
os::SurfaceRef surface = os::System::instance()->makeRgbaSurface(w, h, get_current_color_space());
|
||||
os::SurfaceRef surface =
|
||||
os::System::instance()->makeRgbaSurface(w, h, get_current_color_space(g->display()));
|
||||
convert_image_to_surface(tileImage.get(), get_current_palette(), surface.get(), 0, 0, 0, 0, w, h);
|
||||
|
||||
ui::Paint paint;
|
||||
|
|
|
@ -190,7 +190,9 @@ void Canvas::onResize(ui::ResizeEvent& ev)
|
|||
}
|
||||
|
||||
if (!m_surface || m_surface->width() != w || m_surface->height() != h) {
|
||||
m_surface = system->makeSurface(w, h, get_current_color_space());
|
||||
ui::Display* display = this->display();
|
||||
os::ColorSpaceRef cs = (display ? display->colorSpace() : nullptr);
|
||||
m_surface = system->makeSurface(w, h, cs);
|
||||
callPaint();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
|
||||
namespace app { namespace thumb {
|
||||
|
||||
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
|
||||
os::SurfaceRef get_cel_thumbnail(ui::Display* display,
|
||||
const doc::Cel* cel,
|
||||
const bool scaleUpToFit,
|
||||
const gfx::Size& fitInSize)
|
||||
{
|
||||
|
@ -57,7 +58,7 @@ os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
|
|||
if (os::SurfaceRef thumbnail = os::System::instance()->makeRgbaSurface(
|
||||
thumbnailImage->width(),
|
||||
thumbnailImage->height(),
|
||||
get_current_color_space())) {
|
||||
get_current_color_space(display))) {
|
||||
convert_image_to_surface(thumbnailImage.get(),
|
||||
palette,
|
||||
thumbnail.get(),
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "gfx/size.h"
|
||||
#include "os/surface.h"
|
||||
#include "ui/display.h"
|
||||
|
||||
namespace doc {
|
||||
class Cel;
|
||||
|
@ -22,7 +23,8 @@ class Surface;
|
|||
|
||||
namespace app { namespace thumb {
|
||||
|
||||
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
|
||||
os::SurfaceRef get_cel_thumbnail(ui::Display* display,
|
||||
const doc::Cel* cel,
|
||||
const bool scaleUpToFit,
|
||||
const gfx::Size& fitInSize);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -107,11 +107,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
os::Surface* getCanvas(int w, int h, gfx::Color bgColor)
|
||||
os::Surface* getCanvas(Display* display, int w, int h, gfx::Color bgColor)
|
||||
{
|
||||
assert_ui_thread();
|
||||
|
||||
auto activeCS = get_current_color_space();
|
||||
auto activeCS = get_current_color_space(display);
|
||||
|
||||
if (!m_canvas || m_canvas->width() != w || m_canvas->height() != h ||
|
||||
m_canvas->colorSpace() != activeCS) {
|
||||
|
@ -432,9 +432,9 @@ void ColorSelector::onPaint(ui::PaintEvent& ev)
|
|||
SkCanvas* canvas;
|
||||
bool isSRGB;
|
||||
// TODO compare both color spaces
|
||||
if ((!get_current_color_space() || get_current_color_space()->isSRGB()) &&
|
||||
(!g->getInternalSurface()->colorSpace() ||
|
||||
g->getInternalSurface()->colorSpace()->isSRGB())) {
|
||||
auto displayCs = get_current_color_space(display());
|
||||
auto gCs = g->getInternalSurface()->colorSpace();
|
||||
if ((!displayCs || displayCs->isSRGB()) && (!gCs || gCs->isSRGB())) {
|
||||
// We can render directly in the ui::Graphics surface
|
||||
canvas = &static_cast<os::SkiaSurface*>(g->getInternalSurface())->canvas();
|
||||
isSRGB = true;
|
||||
|
@ -442,7 +442,7 @@ void ColorSelector::onPaint(ui::PaintEvent& ev)
|
|||
else {
|
||||
// We'll paint in the ColorSelector::Painter canvas, and so we
|
||||
// can convert color spaces.
|
||||
painterSurface = painter.getCanvas(rc.w, rc.h, theme->colors.workspace());
|
||||
painterSurface = painter.getCanvas(display(), rc.w, rc.h, theme->colors.workspace());
|
||||
canvas = &static_cast<os::SkiaSurface*>(painterSurface)->canvas();
|
||||
isSRGB = false;
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ void ColorSelector::onPaint(ui::PaintEvent& ev)
|
|||
else
|
||||
#endif // SK_ENABLE_SKSL
|
||||
{
|
||||
painterSurface = painter.getCanvas(rc.w, rc.h, theme->colors.workspace());
|
||||
painterSurface = painter.getCanvas(display(), rc.w, rc.h, theme->colors.workspace());
|
||||
}
|
||||
|
||||
if (painterSurface)
|
||||
|
|
|
@ -58,9 +58,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
// Color space conversion
|
||||
auto convertColor = convert_from_current_to_screen_color_space();
|
||||
|
||||
Paint paint;
|
||||
gfx::Color color = gfx::ColorNone;
|
||||
int w = std::max(rc.w - 1, 1);
|
||||
|
||||
|
@ -110,7 +108,11 @@ public:
|
|||
color = color_utils::color_for_ui(app::Color::fromGray(255 * x / w));
|
||||
break;
|
||||
}
|
||||
g->drawVLine(convertColor(color), rc.x + x, rc.y, rc.h);
|
||||
|
||||
// Color space conversion
|
||||
paint.color(color, get_current_color_space(slider->display()).get());
|
||||
|
||||
g->drawVLine(rc.x + x, rc.y, rc.h, paint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "app/ui/color_wheel.h"
|
||||
|
||||
#include "app/color_spaces.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/pref/preferences.h"
|
||||
|
@ -358,6 +359,9 @@ void ColorWheel::onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc)
|
|||
int n = getHarmonies();
|
||||
int boxsize = std::min(rc.w / 10, rc.h / 10);
|
||||
|
||||
ui::Paint paint;
|
||||
auto cs = get_current_color_space(g->display());
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
app::Color color = getColorInHarmony(i);
|
||||
double angle = color.getHsvHue() - 30.0;
|
||||
|
@ -374,9 +378,10 @@ void ColorWheel::onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc)
|
|||
|
||||
paintColorIndicator(g, pos, color.getHsvValue() < 0.5);
|
||||
|
||||
g->fillRect(
|
||||
gfx::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255),
|
||||
gfx::Rect(rc.x + rc.w - (n - i) * boxsize, rc.y + rc.h - boxsize, boxsize, boxsize));
|
||||
paint.color(gfx::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255), cs.get());
|
||||
g->drawRect(
|
||||
gfx::Rect(rc.x + rc.w - (n - i) * boxsize, rc.y + rc.h - boxsize, boxsize, boxsize),
|
||||
paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ public:
|
|||
int w = tileImage->width();
|
||||
int h = tileImage->height();
|
||||
os::SurfaceRef surface =
|
||||
os::System::instance()->makeRgbaSurface(w, h, get_current_color_space());
|
||||
os::System::instance()->makeRgbaSurface(w, h, get_current_color_space(g->display()));
|
||||
convert_image_to_surface(tileImage.get(),
|
||||
get_current_palette(),
|
||||
surface.get(),
|
||||
|
|
|
@ -970,8 +970,10 @@ void Tabs::createFloatingUILayer(Tab* tab)
|
|||
ASSERT(!m_floatingUILayer);
|
||||
|
||||
ui::Display* display = this->display();
|
||||
os::SurfaceRef surface =
|
||||
os::System::instance()->makeRgbaSurface(tab->width, m_tabsHeight, get_current_color_space());
|
||||
os::SurfaceRef surface = os::System::instance()->makeRgbaSurface(
|
||||
tab->width,
|
||||
m_tabsHeight,
|
||||
get_current_color_space(display));
|
||||
|
||||
// Fill the surface with pink color
|
||||
{
|
||||
|
|
|
@ -2526,7 +2526,7 @@ void Timeline::drawCel(ui::Graphics* g,
|
|||
|
||||
if (!thumb_bounds.isEmpty()) {
|
||||
if (os::SurfaceRef surface =
|
||||
thumb::get_cel_thumbnail(cel, m_scaleUpToFit, thumb_bounds.size())) {
|
||||
thumb::get_cel_thumbnail(g->display(), cel, m_scaleUpToFit, thumb_bounds.size())) {
|
||||
const int t = std::clamp(thumb_bounds.w / 8, 4, 16);
|
||||
draw_checkered_grid(g, thumb_bounds, gfx::Size(t, t), docPref());
|
||||
|
||||
|
@ -2618,7 +2618,8 @@ void Timeline::drawCelOverlay(ui::Graphics* g)
|
|||
return;
|
||||
|
||||
gfx::Rect rc = m_sprite->bounds().fitIn(gfx::Rect(m_thumbnailsOverlayBounds).shrink(1));
|
||||
if (os::SurfaceRef surface = thumb::get_cel_thumbnail(cel, m_scaleUpToFit, rc.size())) {
|
||||
if (os::SurfaceRef surface =
|
||||
thumb::get_cel_thumbnail(g->display(), cel, m_scaleUpToFit, rc.size())) {
|
||||
draw_checkered_grid(g, rc, gfx::Size(8, 8) * ui::guiscale(), docPref());
|
||||
|
||||
g->drawRgbaSurface(surface.get(),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite UI Library
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
@ -31,6 +31,7 @@ public:
|
|||
Display* parentDisplay() { return m_parentDisplay; }
|
||||
os::Window* nativeWindow() const { return m_nativeWindow.get(); }
|
||||
os::SurfaceRef nativeSurface() const;
|
||||
os::ColorSpaceRef colorSpace() const { return m_nativeWindow->colorSpace(); }
|
||||
|
||||
UILayers layers() { return m_layers; }
|
||||
UILayerRef backLayer() { return m_layers.front(); }
|
||||
|
|
|
@ -155,7 +155,7 @@ void Graphics::drawHLine(gfx::Color color, int x, int y, int w)
|
|||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
os::Paint paint;
|
||||
paint.color(color, colorSpace());
|
||||
paint.color(color);
|
||||
m_surface->drawRect(gfx::Rect(m_dx + x, m_dy + y, w, 1), paint);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ void Graphics::drawVLine(gfx::Color color, int x, int y, int h)
|
|||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
os::Paint paint;
|
||||
paint.color(color, colorSpace());
|
||||
paint.color(color);
|
||||
m_surface->drawRect(gfx::Rect(m_dx + x, m_dy + y, 1, h), paint);
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point
|
|||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
os::Paint paint;
|
||||
paint.color(color, colorSpace());
|
||||
paint.color(color);
|
||||
m_surface->drawLine(a, b, paint);
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig)
|
|||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
os::Paint paint;
|
||||
paint.color(color, colorSpace());
|
||||
paint.color(color);
|
||||
paint.style(os::Paint::Stroke);
|
||||
m_surface->drawRect(rc, paint);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig)
|
|||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
os::Paint paint;
|
||||
paint.color(color, colorSpace());
|
||||
paint.color(color);
|
||||
paint.style(os::Paint::Fill);
|
||||
m_surface->drawRect(rc, paint);
|
||||
}
|
||||
|
@ -444,11 +444,11 @@ void Graphics::drawUIText(const std::string& str,
|
|||
|
||||
Paint paint;
|
||||
if (gfx::geta(bg) > 0) { // Paint background
|
||||
paint.color(bg, colorSpace());
|
||||
paint.color(bg);
|
||||
paint.style(os::Paint::Fill);
|
||||
drawRect(gfx::RectF(textBlob->bounds()).offset(pt), paint);
|
||||
}
|
||||
paint.color(fg, colorSpace());
|
||||
paint.color(fg);
|
||||
|
||||
drawTextBlob(textBlob, gfx::PointF(pt), paint);
|
||||
|
||||
|
@ -603,10 +603,10 @@ gfx::Size Graphics::doUIStringAlgorithm(const std::string& str,
|
|||
Paint paint;
|
||||
paint.style(os::Paint::Fill);
|
||||
if (!gfx::is_transparent(bg)) {
|
||||
paint.color(bg, colorSpace());
|
||||
paint.color(bg);
|
||||
drawRect(gfx::RectF(xout, pt.y, rc.w, lineSize.h), paint);
|
||||
}
|
||||
paint.color(fg, colorSpace());
|
||||
paint.color(fg);
|
||||
|
||||
float baselineDelta = -metrics.ascent - lineBlob->baseline();
|
||||
drawTextBlob(lineBlob, gfx::PointF(xout, pt.y + baselineDelta), paint);
|
||||
|
|
|
@ -39,6 +39,11 @@ namespace ui {
|
|||
class Display;
|
||||
|
||||
// Class to render a widget in the screen.
|
||||
//
|
||||
// The gfx::Color parameter is a color in the sRGB color space
|
||||
// (e.g. used to paint theme elements on widgets). If you want to
|
||||
// paint a color from other color space, use the Paint version of each
|
||||
// function.
|
||||
class Graphics {
|
||||
public:
|
||||
Graphics(Display* display, const os::SurfaceRef& surface, int dx, int dy);
|
||||
|
@ -47,6 +52,7 @@ public:
|
|||
int width() const;
|
||||
int height() const;
|
||||
|
||||
Display* display() const { return m_display; }
|
||||
os::Surface* getInternalSurface() { return m_surface.get(); }
|
||||
os::ColorSpace* colorSpace() { return m_surface->colorSpace().get(); }
|
||||
|
||||
|
|
Loading…
Reference in New Issue