File indexing completed on 2024-05-12 15:59:51

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "KisResourcesInterface.h"
0007 
0008 
0009 #include <QString>
0010 #include "kis_assert.h"
0011 #include "KisResourcesInterface_p.h"
0012 
0013 #include "kis_debug.h"
0014 
0015 //#define SANITY_CHECKS
0016 
0017 
0018 KisResourcesInterface::KisResourcesInterface()
0019     : d_ptr(new KisResourcesInterfacePrivate)
0020 {
0021 }
0022 
0023 KisResourcesInterface::KisResourcesInterface(KisResourcesInterfacePrivate *dd)
0024     : d_ptr(dd)
0025 {
0026 }
0027 
0028 KisResourcesInterface::~KisResourcesInterface()
0029 {
0030 
0031 }
0032 
0033 KisResourcesInterface::ResourceSourceAdapter &KisResourcesInterface::source(const QString &type) const
0034 {
0035     Q_D(const KisResourcesInterface);
0036 
0037     // use double-locking for fetching the source
0038 
0039     ResourceSourceAdapter *source = 0;
0040 
0041     {
0042         QReadLocker l(&d->lock);
0043         source = d->findExistingSource(type);
0044         if (source) return *source;
0045     }
0046 
0047     {
0048         QWriteLocker l(&d->lock);
0049         source = d->findExistingSource(type);
0050         if (source) return *source;
0051 
0052         source = createSourceImpl(type);
0053 
0054         std::unique_ptr<ResourceSourceAdapter> sourcePtr(source);
0055         d->sourceAdapters.emplace(type, std::move(sourcePtr));
0056     }
0057 
0058     KIS_ASSERT(source);
0059     return *source;
0060 }
0061 
0062 KisResourcesInterface::ResourceSourceAdapter::ResourceSourceAdapter(const QString &type)
0063     : m_type(type)
0064 {
0065 }
0066 
0067 KisResourcesInterface::ResourceSourceAdapter::~ResourceSourceAdapter()
0068 {
0069 }
0070 
0071 KoResourceSP KisResourcesInterface::ResourceSourceAdapter::bestMatch(const QString md5, const QString filename, const QString name)
0072 {
0073     QVector<QPair<KoResourceSP, int>> foundResources;
0074 
0075     if (!md5.isEmpty()) {
0076         Q_FOREACH (KoResourceSP res, resourcesForMD5(md5)) {
0077             int penalty = 0;
0078 
0079             if (!res->active()) {
0080                 penalty += 100;
0081             }
0082 
0083             if (!filename.isEmpty() && filename != res->filename()) {
0084                 /// filename is more important than name, so it gives
0085                 /// higher penalty
0086                 penalty += 2;
0087             }
0088 
0089             if (!name.isEmpty() && name != res->name()) {
0090                 penalty++;
0091             }
0092 
0093             foundResources.append(qMakePair(res, penalty));
0094         }
0095     }
0096 
0097 #ifdef SANITY_CHECKS
0098     /**
0099      * When we request a resource using MD5, but it is found only via its
0100      * filename, it is, most probably, a problem with the preset. Namely,
0101      * the MD5 tag saved into the preset is wrong. Let's just warn about
0102      * that.
0103      */
0104     const bool warnAboutIncorrectMd5Fetch =
0105         foundResources.isEmpty() && !md5.isEmpty();
0106 #endif
0107 
0108     if (foundResources.isEmpty()) {
0109         if (!filename.isEmpty()) {
0110             Q_FOREACH (KoResourceSP res, resourcesForFilename(filename)) {
0111                 int penalty = 0;
0112 
0113                 if (!res->active()) {
0114                     penalty += 100;
0115                 }
0116 
0117                 if (!name.isEmpty() && name != res->name()) {
0118                     penalty++;
0119                 }
0120 
0121                 foundResources.append(qMakePair(res, penalty));
0122             }
0123         } else if (!name.isEmpty()) {
0124             Q_FOREACH (KoResourceSP res, resourcesForName(name)) {
0125                 int penalty = 0;
0126 
0127                 if (!res->active()) {
0128                     penalty += 100;
0129                 }
0130 
0131                 foundResources.append(qMakePair(res, penalty));
0132             }
0133         }
0134     }
0135 
0136     auto it = std::min_element(foundResources.begin(), foundResources.end(),
0137                                [] (const QPair<KoResourceSP, int> &lhs,
0138                                const QPair<KoResourceSP, int> &rhs) {return lhs.second < rhs.second;});
0139 
0140     KoResourceSP result = it != foundResources.end() ? it->first : KoResourceSP();
0141 
0142 #ifdef SANITY_CHECKS
0143     if (warnAboutIncorrectMd5Fetch && result) {
0144         qWarning() << "KisResourcesInterface::ResourceSourceAdapter::bestMatch: failed to fetch a resource using md5; falling back for filename...";
0145         qWarning() << "    requested:" << ppVar(md5) << ppVar(filename) << ppVar(name);
0146         qWarning() << "    found:" << result;
0147     }
0148 #endif
0149 
0150     return result;
0151 }
0152 
0153 KoResourceLoadResult KisResourcesInterface::ResourceSourceAdapter::bestMatchLoadResult(const QString md5, const QString filename, const QString name)
0154 {
0155     KoResourceSP resource = bestMatch(md5, filename, name);
0156     return
0157         resource ?
0158         KoResourceLoadResult(resource) :
0159         KoResourceLoadResult(KoResourceSignature(m_type, md5, filename, name));
0160 }