Commit afa195a2 authored by Bernhard Liebl's avatar Bernhard Liebl

no dynamic allocations on KoColor

parent ac427aa1
This diff is collapsed.
......@@ -24,7 +24,10 @@
#include <QMetaType>
#include "kritapigment_export.h"
#include "KoColorConversionTransformation.h"
#include "KoColorSpaceRegistry.h"
#include "KoColorSpaceTraits.h"
#include <boost/operators.hpp>
#include "kis_assert.h"
class QDomDocument;
......@@ -41,10 +44,17 @@ class KRITAPIGMENT_EXPORT KoColor : public boost::equality_comparable<KoColor>
{
public:
static void init();
/// Create an empty KoColor. It will be valid, but also black and transparent
KoColor();
KoColor() {
const KoColor * const prefab = s_prefab;
// assert that KoColor::init was called and everything is set up properly.
KIS_ASSERT_X(prefab != nullptr, "KoColor::KoColor()", "KoColor not initialized yet.");
~KoColor();
*this = *prefab;
}
/// Create a null KoColor. It will be valid, but all channels will be set to 0
explicit KoColor(const KoColorSpace * colorSpace);
......@@ -59,19 +69,40 @@ public:
KoColor(const KoColor &src, const KoColorSpace * colorSpace);
/// Copy constructor -- deep copies the colors.
KoColor(const KoColor & rhs);
KoColor(const KoColor & rhs) {
*this = rhs;
}
/**
* assignment operator to copy the data from the param color into this one.
* @param other the color we are going to copy
* @return this color
*/
KoColor &operator=(const KoColor &other);
inline KoColor &operator=(const KoColor &rhs) {
if (&rhs == this) {
return *this;
}
m_colorSpace = rhs.m_colorSpace;
m_size = rhs.m_size;
memcpy(m_data, rhs.m_data, m_size);
assertPermanentColorspace();
return *this;
}
bool operator==(const KoColor &other) const;
bool operator==(const KoColor &other) const {
if (*colorSpace() != *other.colorSpace())
return false;
Q_ASSERT(m_size == other.m_size);
return memcmp(m_data, other.m_data, m_size) == 0;
}
/// return the current colorSpace
const KoColorSpace * colorSpace() const;
const KoColorSpace * colorSpace() const {
return m_colorSpace;
}
/// return the current profile
const KoColorProfile *profile() const;
......@@ -112,21 +143,25 @@ public:
qreal opacityF() const;
/// Convenient function for converting from a QColor
void fromQColor(const QColor& c) const;
void fromQColor(const QColor& c);
/**
* @return the buffer associated with this color object to be used with the
* transformation object created by the color space of this KoColor
* or to copy to a different buffer from the same color space
*/
quint8 * data();
quint8 * data() {
return m_data;
}
/**
* @return the buffer associated with this color object to be used with the
* transformation object created by the color space of this KoColor
* or to copy to a different buffer from the same color space
*/
const quint8 * data() const;
const quint8 * data() const {
return m_data;
}
/**
* Serialize this color following Create's swatch color specification available
......@@ -184,8 +219,19 @@ public:
#endif
private:
class Private;
Private * const d;
inline void assertPermanentColorspace() {
#ifndef NODEBUG
if (m_colorSpace) {
Q_ASSERT(*m_colorSpace == *KoColorSpaceRegistry::instance()->permanentColorspace(m_colorSpace));
}
#endif
}
const KoColorSpace *m_colorSpace;
quint8 m_data[MAX_PIXEL_SIZE];
quint8 m_size;
static const KoColor *s_prefab;
};
Q_DECLARE_METATYPE(KoColor)
......
......@@ -27,6 +27,8 @@
#include "KoColorSpace.h"
#include "KoColorSpaceRegistry.h"
#include "kis_assert.h"
struct Q_DECL_HIDDEN KoColorSpaceFactory::Private {
QList<KoColorProfile*> colorprofiles;
QList<KoColorSpace*> colorspaces;
......@@ -94,6 +96,7 @@ const KoColorSpace *KoColorSpaceFactory::grabColorSpace(const KoColorProfile * p
if (it == d->availableColorspaces.end()) {
cs = createColorSpace(profile);
KIS_ASSERT_X(cs != nullptr, "KoColorSpaceFactory::grabColorSpace", "createColorSpace returned nullptr.");
if (cs) {
d->availableColorspaces[profile->name()] = cs;
}
......
......@@ -408,6 +408,7 @@ const KoColorProfile *KoColorSpaceRegistry::Private::profileForCsIdWithFallbackI
QList<const KoColorProfile *> profiles = profileStorage.profilesFor(colorSpaceFactoryRegistry.value(csID));
if (profiles.isEmpty() || !profiles.first()) {
dbgPigmentCSRegistry << "Couldn't fetch a fallback profile:" << profileName;
qWarning() << "profileForCsIdWithFallbackImpl couldn't fetch a fallback profile for " << qUtf8Printable(profileName);
return 0;
}
......@@ -437,6 +438,7 @@ const KoColorSpace *KoColorSpaceRegistry::Private::lazyCreateColorSpaceImpl(cons
cs = csf->grabColorSpace(profile);
if (!cs) {
dbgPigmentCSRegistry << "Unable to create color space";
qWarning() << "lazyCreateColorSpaceImpl was unable to create a color space for " << csID;
return 0;
}
......
......@@ -26,6 +26,10 @@
#include "KoColorSpaceMaths.h"
#include "DebugPigment.h"
const int MAX_CHANNELS_TYPE_SIZE = sizeof(double);
const int MAX_CHANNELS_NB = 5;
const int MAX_PIXEL_SIZE = MAX_CHANNELS_NB * MAX_CHANNELS_TYPE_SIZE;
/**
* This class is the base class to define the main characteristics of a colorspace
* which inherits KoColorSpaceAbstract.
......@@ -36,7 +40,7 @@
* - _channels_nb_ is the total number of channels in an image (for example RGB is 3 but RGBA is four)
* - _alpha_pos_ is the position of the alpha channel among the channels, if there is no alpha channel,
* then _alpha_pos_ is set to -1
*
*
* For instance a colorspace of three color channels and alpha channel in 16bits,
* will be defined as KoColorSpaceTrait\<quint16, 4, 3\>. The same without the alpha
* channel is KoColorSpaceTrait\<quint16,3,-1\>
......@@ -44,25 +48,28 @@
*/
template<typename _channels_type_, int _channels_nb_, int _alpha_pos_>
struct KoColorSpaceTrait {
static_assert(sizeof(_channels_type_) <= MAX_CHANNELS_TYPE_SIZE, "MAX_CHANNELS_TYPE_SIZE too small");
static_assert(_channels_nb_ <= MAX_CHANNELS_NB, "MAX_CHANNELS_NB too small");
/// the type of the value of the channels of this color space
typedef _channels_type_ channels_type;
/// the number of channels in this color space
static const quint32 channels_nb = _channels_nb_;
/// the position of the alpha channel in the channels of the pixel (or -1 if no alpha
/// channel.
static const qint32 alpha_pos = _alpha_pos_;
/// the number of bit for each channel
static const int depth = KoColorSpaceMathsTraits<_channels_type_>::bits;
/**
* @return the size in byte of one pixel
*/
static const quint32 pixelSize = channels_nb * sizeof(channels_type);
/**
* @return the value of the alpha channel for this pixel in the 0..255 range
*/
......@@ -71,13 +78,13 @@ struct KoColorSpaceTrait {
channels_type c = nativeArray(U8_pixel)[alpha_pos];
return KoColorSpaceMaths<channels_type, quint8>::scaleToA(c);
}
inline static qreal opacityF(const quint8 * U8_pixel) {
if (alpha_pos < 0) return OPACITY_OPAQUE_F;
channels_type c = nativeArray(U8_pixel)[alpha_pos];
return KoColorSpaceMaths<channels_type, qreal>::scaleToA(c);
}
/**
* Set the alpha channel for this pixel from a value in the 0..255 range
*/
......@@ -89,7 +96,7 @@ struct KoColorSpaceTrait {
nativeArray(pixels)[alpha_pos] = valpha;
}
}
inline static void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) {
if (alpha_pos < 0) return;
qint32 psize = pixelSize;
......@@ -98,28 +105,28 @@ struct KoColorSpaceTrait {
nativeArray(pixels)[alpha_pos] = valpha;
}
}
/**
* Convenient function for transforming a quint8* array in a pointer of the native channels type
*/
inline static const channels_type* nativeArray(const quint8 * a) {
return reinterpret_cast<const channels_type*>(a);
}
/**
* Convenient function for transforming a quint8* array in a pointer of the native channels type
*/
inline static channels_type* nativeArray(quint8 * a) {
return reinterpret_cast< channels_type*>(a);
}
/**
* Allocate nPixels pixels for this colorspace.
*/
inline static quint8* allocate(quint32 nPixels) {
return new quint8[ nPixels * pixelSize ];
}
inline static void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) {
const channels_type* src = nativeArray(srcPixel);
channels_type* dst = nativeArray(dstPixel);
......@@ -131,7 +138,7 @@ struct KoColorSpaceTrait {
}
}
}
inline static QString channelValueText(const quint8 *pixel, quint32 channelIndex) {
if (channelIndex > channels_nb) return QString("Error");
channels_type c = nativeArray(pixel)[channelIndex];
......
......@@ -282,6 +282,9 @@ void KisApplication::addResourceTypes()
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/input/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/pykrita/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/symbols/");
// Indicate that it is now safe for users of KoResourcePaths to load resources
KoResourcePaths::setReady();
}
void KisApplication::loadResources()
......@@ -418,6 +421,10 @@ bool KisApplication::start(const KisApplicationArguments &args)
processEvents();
addResourceTypes();
// now we're set up, and the LcmsEnginePlugin will have access to resource paths for color management,
// we can finally initialize KoColor.
KoColor::init();
// Load all resources and tags before the plugins do that
loadResources();
......
......@@ -141,6 +141,8 @@ public:
QMutex relativesMutex;
QMutex absolutesMutex;
bool ready = false; // Paths have been initialized
QStringList aliases(const QString &type)
{
QStringList r;
......@@ -548,3 +550,13 @@ QString KoResourcePaths::locateLocalInternal(const QString &type, const QString
debugWidgetUtils << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path;
return path + '/' + filename;
}
void KoResourcePaths::setReady()
{
s_instance->d->ready = true;
}
void KoResourcePaths::assertReady()
{
KIS_ASSERT_X(s_instance->d->ready, "KoResourcePaths::assertReady", "Resource paths are not ready yet.");
}
......@@ -219,6 +219,17 @@ public:
**/
static QString locateLocal(const char *type, const QString &filename, bool createDir = false);
/**
* Indicate that resource paths have been initialized and users
* of this class may expect to load resources from the proper paths.
*/
static void setReady();
/**
* Assert that all resource paths have been initialized.
*/
static void assertReady();
private:
void addResourceTypeInternal(const QString &type, const QString &basetype,
......
......@@ -30,6 +30,8 @@
#include <klocalizedstring.h>
#include <QDebug>
#include "kis_assert.h"
#include <KoBasicHistogramProducers.h>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>
......@@ -84,6 +86,10 @@ K_PLUGIN_FACTORY_WITH_JSON(PluginFactory, "kolcmsengine.json",
LcmsEnginePlugin::LcmsEnginePlugin(QObject *parent, const QVariantList &)
: QObject(parent)
{
// We need all resource paths to be properly initialized via KisApplication, otherwise we will
// initialize this instance with lacking color profiles which will cause lookup errors later on.
KoResourcePaths::assertReady();
// Set the lmcs error reporting function
cmsSetLogErrorHandler(&lcms2LogErrorHandlerFunction);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment