summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
authorDaniel Wilhelm <shieldwed@outlook.com>2018-06-30 12:43:08 +0200
committerDaniel Wilhelm <shieldwed@outlook.com>2018-06-30 12:43:08 +0200
commita98326eb2954ac1e79f5eac28dbeab3ec15e047f (patch)
treebb16257a1894b488e365851273735ec13a9442ef /wx+
parent10.0 (diff)
downloadFreeFileSync-a98326eb2954ac1e79f5eac28dbeab3ec15e047f.tar.gz
FreeFileSync-a98326eb2954ac1e79f5eac28dbeab3ec15e047f.tar.bz2
FreeFileSync-a98326eb2954ac1e79f5eac28dbeab3ec15e047f.zip
10.1
Diffstat (limited to 'wx+')
-rwxr-xr-xwx+/async_task.h6
-rwxr-xr-xwx+/grid.cpp4
-rwxr-xr-xwx+/http.cpp279
-rwxr-xr-xwx+/http.h49
-rwxr-xr-xwx+/image_holder.h10
-rwxr-xr-xwx+/image_resources.cpp129
-rwxr-xr-xwx+/image_tools.cpp2
-rwxr-xr-xwx+/zlib_wrap.h6
8 files changed, 43 insertions, 442 deletions
diff --git a/wx+/async_task.h b/wx+/async_task.h
index 1d64e262..8c2602ca 100755
--- a/wx+/async_task.h
+++ b/wx+/async_task.h
@@ -49,12 +49,12 @@ public:
bool resultReady () const override { return isReady(asyncResult_); }
void evaluateResult() override
{
- evalResult(IsSameType<ResultType, void>());
+ evalResult(std::is_same<ResultType, void>());
}
private:
- void evalResult(FalseType /*void result type*/) { evalOnGui_(asyncResult_.get()); }
- void evalResult(TrueType /*void result type*/) { asyncResult_.get(); evalOnGui_(); }
+ void evalResult(std::false_type /*void result type*/) { evalOnGui_(asyncResult_.get()); }
+ void evalResult(std::true_type /*void result type*/) { asyncResult_.get(); evalOnGui_(); }
std::future<ResultType> asyncResult_;
Fun evalOnGui_; //keep "evalOnGui" strictly separated from async thread: in particular do not copy in thread!
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index a1beee01..adc0615c 100755
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -169,12 +169,12 @@ wxSize GridData::drawCellText(wxDC& dc, const wxRect& rect, const std::wstring&
if (alignment & wxALIGN_RIGHT) //note: wxALIGN_LEFT == 0!
pt.x += rect.width - extentTrunc.GetWidth();
else if (alignment & wxALIGN_CENTER_HORIZONTAL)
- pt.x += (rect.width - extentTrunc.GetWidth()) / 2;
+ pt.x += static_cast<int>(std::floor((rect.width - extentTrunc.GetWidth()) / 2.0)); //round down negative values, too!
if (alignment & wxALIGN_BOTTOM) //note: wxALIGN_TOP == 0!
pt.y += rect.height - extentTrunc.GetHeight();
else if (alignment & wxALIGN_CENTER_VERTICAL)
- pt.y += (rect.height - extentTrunc.GetHeight()) / 2;
+ pt.y += static_cast<int>(std::floor((rect.height - extentTrunc.GetHeight()) / 2.0)); //round down negative values, too!
RecursiveDcClipper clip(dc, rect);
dc.DrawText(textTrunc, pt);
diff --git a/wx+/http.cpp b/wx+/http.cpp
deleted file mode 100755
index 1526d30f..00000000
--- a/wx+/http.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-// *****************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
-// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
-// *****************************************************************************
-
-#include "http.h"
-
- #include <wx/app.h>
- #include <zen/thread.h> //std::thread::id
- #include <wx/protocol/http.h>
-
-using namespace zen;
-
-
-namespace
-{
-
-struct UrlRedirectError
-{
- UrlRedirectError(const std::wstring& url) : newUrl(url) {}
- std::wstring newUrl;
-};
-}
-
-
-class HttpInputStream::Impl
-{
-public:
- Impl(const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO, //throw SysError, UrlRedirectError
- const std::string* postParams) : //issue POST if bound, GET otherwise
- notifyUnbufferedIO_(notifyUnbufferedIO)
- {
- ZEN_ON_SCOPE_FAIL( cleanup(); /*destructor call would lead to member double clean-up!!!*/ );
-
- //assert(!startsWith(url, L"https:", CmpAsciiNoCase())); //not supported by wxHTTP!
-
- const std::wstring urlFmt = afterFirst(url, L"://", IF_MISSING_RETURN_NONE);
- const std::wstring server = beforeFirst(urlFmt, L'/', IF_MISSING_RETURN_ALL);
- const std::wstring page = L'/' + afterFirst(urlFmt, L'/', IF_MISSING_RETURN_NONE);
-
- assert(std::this_thread::get_id() == mainThreadId);
- assert(wxApp::IsMainLoopRunning());
-
- webAccess_.SetHeader(L"User-Agent", userAgent);
- webAccess_.SetTimeout(10 /*[s]*/); //default: 10 minutes: WTF are these wxWidgets people thinking???
-
- if (!webAccess_.Connect(server)) //will *not* fail for non-reachable url here!
- throw SysError(L"wxHTTP::Connect");
-
- if (postParams)
- if (!webAccess_.SetPostText(L"application/x-www-form-urlencoded", utfTo<wxString>(*postParams)))
- throw SysError(L"wxHTTP::SetPostText");
-
- httpStream_.reset(webAccess_.GetInputStream(page)); //pass ownership
- const int sc = webAccess_.GetResponse();
-
- //http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection
- if (sc / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too!
- {
- const std::wstring newUrl(webAccess_.GetHeader(L"Location"));
- if (newUrl.empty())
- throw SysError(L"Unresolvable redirect. Empty target Location.");
-
- throw UrlRedirectError(newUrl);
- }
-
- if (sc != 200) //HTTP_STATUS_OK
- throw SysError(replaceCpy<std::wstring>(L"HTTP status code %x.", L"%x", numberTo<std::wstring>(sc)));
-
- if (!httpStream_ || webAccess_.GetError() != wxPROTO_NOERR)
- throw SysError(L"wxHTTP::GetError (" + numberTo<std::wstring>(webAccess_.GetError()) + L")");
- }
-
- ~Impl() { cleanup(); }
-
- size_t read(void* buffer, size_t bytesToRead) //throw SysError, X; return "bytesToRead" bytes unless end of stream!
- {
- const size_t blockSize = getBlockSize();
- assert(memBuf_.size() >= blockSize);
- assert(bufPos_ <= bufPosEnd_ && bufPosEnd_ <= memBuf_.size());
-
- char* it = static_cast<char*>(buffer);
- char* const itEnd = it + bytesToRead;
- for (;;)
- {
- const size_t junkSize = std::min(static_cast<size_t>(itEnd - it), bufPosEnd_ - bufPos_);
- std::memcpy(it, &memBuf_[0] + bufPos_, junkSize);
- bufPos_ += junkSize;
- it += junkSize;
-
- if (it == itEnd)
- break;
- //--------------------------------------------------------------------
- const size_t bytesRead = tryRead(&memBuf_[0], blockSize); //throw SysError; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0
- bufPos_ = 0;
- bufPosEnd_ = bytesRead;
-
- if (notifyUnbufferedIO_) notifyUnbufferedIO_(bytesRead); //throw X
-
- if (bytesRead == 0) //end of file
- break;
- }
- return it - static_cast<char*>(buffer);
- }
-
- size_t getBlockSize() const { return 64 * 1024; }
-
-private:
- size_t tryRead(void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF!
- {
- if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
- assert(bytesToRead == getBlockSize());
-
- httpStream_->Read(buffer, bytesToRead);
-
- const wxStreamError ec = httpStream_->GetLastError();
- if (ec != wxSTREAM_NO_ERROR && ec != wxSTREAM_EOF)
- throw SysError(L"wxInputStream::GetLastError (" + numberTo<std::wstring>(httpStream_->GetLastError()) + L")");
-
- const size_t bytesRead = httpStream_->LastRead();
- //"if there are not enough bytes in the stream right now, LastRead() value will be
- // less than size but greater than 0. If it is 0, it means that EOF has been reached."
- assert(bytesRead > 0 || ec == wxSTREAM_EOF);
- if (bytesRead > bytesToRead) //better safe than sorry
- throw SysError(L"InternetReadFile: buffer overflow.");
-
- return bytesRead; //"zero indicates end of file"
- }
-
- Impl (const Impl&) = delete;
- Impl& operator=(const Impl&) = delete;
-
- void cleanup()
- {
- }
-
- wxHTTP webAccess_;
- std::unique_ptr<wxInputStream> httpStream_; //must be deleted BEFORE webAccess is closed
-
- const IOCallback notifyUnbufferedIO_; //throw X
-
- std::vector<char> memBuf_ = std::vector<char>(getBlockSize());
- size_t bufPos_ = 0; //buffered I/O; see file_io.cpp
- size_t bufPosEnd_ = 0; //
-};
-
-
-HttpInputStream::HttpInputStream(std::unique_ptr<Impl>&& pimpl) : pimpl_(std::move(pimpl)) {}
-
-HttpInputStream::~HttpInputStream() {}
-
-size_t HttpInputStream::read(void* buffer, size_t bytesToRead) { return pimpl_->read(buffer, bytesToRead); } //throw SysError, X; return "bytesToRead" bytes unless end of stream!
-
-size_t HttpInputStream::getBlockSize() const { return pimpl_->getBlockSize(); }
-
-std::string HttpInputStream::readAll() { return bufferedLoad<std::string>(*pimpl_); } //throw SysError, X;
-
-namespace
-{
-std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO, //throw SysError
- const std::string* postParams) //issue POST if bound, GET otherwise
-{
- std::wstring urlRed = url;
- //"A user agent should not automatically redirect a request more than five times, since such redirections usually indicate an infinite loop."
- for (int redirects = 0; redirects < 6; ++redirects)
- try
- {
- return std::make_unique<HttpInputStream::Impl>(urlRed, userAgent, notifyUnbufferedIO, postParams); //throw SysError, UrlRedirectError
- }
- catch (const UrlRedirectError& e) { urlRed = e.newUrl; }
- throw SysError(L"Too many redirects.");
-}
-
-
-//encode into "application/x-www-form-urlencoded"
-std::string urlencode(const std::string& str)
-{
- std::string out;
- for (const char c : str) //follow PHP spec: https://github.com/php/php-src/blob/master/ext/standard/url.c#L500
- if (c == ' ')
- out += '+';
- else if (('0' <= c && c <= '9') ||
- ('A' <= c && c <= 'Z') ||
- ('a' <= c && c <= 'z') ||
- c == '-' || c == '.' || c == '_') //note: "~" is encoded by PHP!
- out += c;
- else
- {
- const std::pair<char, char> hex = hexify(c);
-
- out += '%';
- out += hex.first;
- out += hex.second;
- }
- return out;
-}
-
-
-std::string urldecode(const std::string& str)
-{
- std::string out;
- for (size_t i = 0; i < str.size(); ++i)
- {
- const char c = str[i];
- if (c == '+')
- out += ' ';
- else if (c == '%' && str.size() - i >= 3 &&
- isHexDigit(str[i + 1]) &&
- isHexDigit(str[i + 2]))
- {
- out += unhexify(str[i + 1], str[i + 2]);
- i += 2;
- }
- else
- out += c;
- }
- return out;
-}
-}
-
-
-std::string zen::xWwwFormUrlEncode(const std::vector<std::pair<std::string, std::string>>& paramPairs)
-{
- std::string output;
- for (const auto& pair : paramPairs)
- output += urlencode(pair.first) + '=' + urlencode(pair.second) + '&';
- //encode both key and value: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
- if (!output.empty())
- output.pop_back();
- return output;
-}
-
-
-std::vector<std::pair<std::string, std::string>> zen::xWwwFormUrlDecode(const std::string& str)
-{
- std::vector<std::pair<std::string, std::string>> output;
-
- for (const std::string& nvPair : split(str, '&', SplitType::SKIP_EMPTY))
- output.emplace_back(urldecode(beforeFirst(nvPair, '=', IF_MISSING_RETURN_ALL)),
- urldecode(afterFirst (nvPair, '=', IF_MISSING_RETURN_NONE)));
- return output;
-}
-
-
-HttpInputStream zen::sendHttpPost(const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO,
- const std::vector<std::pair<std::string, std::string>>& postParams) //throw SysError
-{
- const std::string encodedParams = xWwwFormUrlEncode(postParams);
- return sendHttpRequestImpl(url, userAgent, notifyUnbufferedIO, &encodedParams); //throw SysError
-}
-
-
-HttpInputStream zen::sendHttpGet(const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO) //throw SysError
-{
- return sendHttpRequestImpl(url, userAgent, notifyUnbufferedIO, nullptr); //throw SysError
-}
-
-
-bool zen::internetIsAlive() //noexcept
-{
- assert(std::this_thread::get_id() == mainThreadId);
-
- const wxString server = L"www.google.com";
- const wxString page = L"/";
-
- wxHTTP webAccess;
- webAccess.SetTimeout(10 /*[s]*/); //default: 10 minutes: WTF are these wxWidgets people thinking???
-
- if (!webAccess.Connect(server)) //will *not* fail for non-reachable url here!
- return false;
-
- std::unique_ptr<wxInputStream> httpStream(webAccess.GetInputStream(page)); //call before checking wxHTTP::GetResponse()
- const int sc = webAccess.GetResponse();
- //attention: http://www.google.com/ might redirect to "https" => don't follow, just return "true"!!!
- return sc / 100 == 2 || //e.g. 200
- sc / 100 == 3; //e.g. 301, 302, 303, 307... when in doubt, consider internet alive!
-}
diff --git a/wx+/http.h b/wx+/http.h
deleted file mode 100755
index bbfa3a74..00000000
--- a/wx+/http.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// *****************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
-// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
-// *****************************************************************************
-
-#ifndef HTTP_H_879083425703425702
-#define HTTP_H_879083425703425702
-
-#include <zen/file_error.h>
-#include <zen/serialize.h>
-
-namespace zen
-{
-/*
- TREAD-SAFETY
- ------------
- Windows: WinInet-based => may be called from worker thread, supports HTTPS
- Linux: wxWidgets-based => don't call from worker thread
-*/
-class HttpInputStream
-{
-public:
- //support zen/serialize.h buffered input stream concept
- size_t read(void* buffer, size_t bytesToRead); //throw SysError, X; return "bytesToRead" bytes unless end of stream!
- std::string readAll(); //throw SysError, X
-
- size_t getBlockSize() const;
-
- class Impl;
- HttpInputStream(std::unique_ptr<Impl>&& pimpl);
- HttpInputStream(HttpInputStream&&) = default;
- ~HttpInputStream();
-
-private:
- std::unique_ptr<Impl> pimpl_;
-};
-
-
-HttpInputStream sendHttpGet (const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO); //throw SysError
-HttpInputStream sendHttpPost(const std::wstring& url, const std::wstring& userAgent, const IOCallback& notifyUnbufferedIO,
- const std::vector<std::pair<std::string, std::string>>& postParams); //throw SysError
-bool internetIsAlive(); //noexcept
-
-std::string xWwwFormUrlEncode(const std::vector<std::pair<std::string, std::string>>& paramPairs);
-std::vector<std::pair<std::string, std::string>> xWwwFormUrlDecode(const std::string& str);
-}
-
-#endif //HTTP_H_879083425703425702
diff --git a/wx+/image_holder.h b/wx+/image_holder.h
index 6804d5fc..f4bf3c8a 100755
--- a/wx+/image_holder.h
+++ b/wx+/image_holder.h
@@ -18,15 +18,15 @@ struct ImageHolder //prepare conversion to wxImage as much as possible while sta
{
ImageHolder() {}
- ImageHolder(int w, int h, bool withAlpha) : //init with allocated memory
+ ImageHolder(int w, int h, bool withAlpha) : //init with memory allocated
width_(w), height_(h),
rgb_(static_cast<unsigned char*>(::malloc(w * h * 3))),
alpha_(withAlpha ? static_cast<unsigned char*>(::malloc(w * h)) : nullptr) {}
- ImageHolder (ImageHolder&& tmp) = default; //
- ImageHolder& operator=(ImageHolder&& tmp) = default; //move semantics only!
- ImageHolder (const ImageHolder&) = delete; //
- ImageHolder& operator=(const ImageHolder&) = delete; //
+ ImageHolder (ImageHolder&&) noexcept = default; //
+ ImageHolder& operator=(ImageHolder&&) noexcept = default; //move semantics only!
+ ImageHolder (const ImageHolder&) = delete; //
+ ImageHolder& operator=(const ImageHolder&) = delete; //
explicit operator bool() const { return rgb_.get() != nullptr; }
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index e361515a..bbeeff8b 100755
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -26,8 +26,6 @@ using namespace zen;
namespace
{
-
-
ImageHolder dpiScale(int width, int height, int dpiWidth, int dpiHeight, const unsigned char* imageRgb, const unsigned char* imageAlpha, int hqScale)
{
assert(imageRgb && imageAlpha); //see convertToVanillaImage()
@@ -84,113 +82,41 @@ ImageHolder dpiScale(int width, int height, int dpiWidth, int dpiHeight, const u
}
-struct WorkItem
+auto getScalerTask(const wxString& name, const wxImage& img, int hqScale, Protected<std::vector<std::pair<std::wstring, ImageHolder>>>& result)
{
- std::wstring name; //don't trust wxString to be thread-safe like an int
- int width = 0;
- int height = 0;
- int dpiWidth = 0;
- int dpiHeight = 0;
- const unsigned char* rgb = nullptr;
- const unsigned char* alpha = nullptr;
-};
-
-
-class WorkLoad
-{
-public:
- void add(const WorkItem& wi) //context of main thread
- {
- assert(std::this_thread::get_id() == mainThreadId);
- {
- std::lock_guard<std::mutex> dummy(lockWork_);
- workLoad_.push_back(wi);
- }
- conditionNewWork_.notify_all();
- }
-
- void noMoreWork()
+ return [name = copyStringTo<std::wstring>(name), //don't trust wxString to be thread-safe like an int
+ width = img.GetWidth(),
+ height = img.GetHeight(),
+ dpiWidth = fastFromDIP(img.GetWidth()),
+ dpiHeight = fastFromDIP(img.GetHeight()), //don't call fastFromDIP() from worker thread (wxWidgets function!)
+ rgb = img.GetData(),
+ alpha = img.GetAlpha(),
+ hqScale, &result]
{
- assert(std::this_thread::get_id() == mainThreadId);
- {
- std::lock_guard<std::mutex> dummy(lockWork_);
- expectMoreWork_ = false;
- }
- conditionNewWork_.notify_all();
- }
-
- //context of worker thread, blocking:
- Opt<WorkItem> extractNext() //throw ThreadInterruption
- {
- assert(std::this_thread::get_id() != mainThreadId);
- std::unique_lock<std::mutex> dummy(lockWork_);
-
- interruptibleWait(conditionNewWork_, dummy, [this] { return !workLoad_.empty() || !expectMoreWork_; }); //throw ThreadInterruption
-
- if (!workLoad_.empty())
- {
- WorkItem wi = std::move(workLoad_. back()); //
- /**/ workLoad_.pop_back(); //yes, no strong exception guarantee (std::bad_alloc)
- return std::move(wi); //
- }
- return NoValue();
- }
-
-private:
- std::mutex lockWork_;
- std::vector<WorkItem> workLoad_;
- std::condition_variable conditionNewWork_; //signal event: data for processing available
- bool expectMoreWork_ = true;
-};
+ ImageHolder ih = dpiScale(width, height,
+ dpiWidth, dpiHeight,
+ rgb, alpha, hqScale);
+ result.access([&](std::vector<std::pair<std::wstring, ImageHolder>>& r) { r.emplace_back(name, std::move(ih)); });
+ };
+}
class DpiParallelScaler
{
public:
- DpiParallelScaler(int hqScale)
- {
- assert(hqScale > 1);
- const int threadCount = std::max<int>(std::thread::hardware_concurrency(), 1); //hardware_concurrency() == 0 if "not computable or well defined"
-
- for (int i = 0; i < threadCount; ++i)
- worker_.push_back([hqScale, &workload = workload_, &result = result_]
- {
- setCurrentThreadName("xBRZ Scaler");
- while (Opt<WorkItem> wi = workload.extractNext()) //throw ThreadInterruption
- {
- ImageHolder ih = dpiScale(wi->width, wi->height,
- wi->dpiWidth, wi->dpiHeight,
- wi->rgb, wi->alpha, hqScale);
- result.access([&](std::vector<std::pair<std::wstring, ImageHolder>>& r) { r.emplace_back(wi->name, std::move(ih)); });
- }
- });
- }
+ DpiParallelScaler(int hqScale) : hqScale_(hqScale) { assert(hqScale > 1); }
- ~DpiParallelScaler()
- {
- for (InterruptibleThread& w : worker_)
- w.interrupt();
-
- for (InterruptibleThread& w : worker_)
- if (w.joinable())
- w.join();
- }
+ ~DpiParallelScaler() { threadGroup_ = zen::NoValue(); } //DpiParallelScaler must out-live threadGroup!!!
void add(const wxString& name, const wxImage& img)
{
imgKeeper_.push_back(img); //retain (ref-counted) wxImage so that the rgb/alpha pointers remain valid after passed to threads
- workload_.add({ copyStringTo<std::wstring>(name),
- img.GetWidth(), img.GetHeight(),
- fastFromDIP(img.GetWidth()), fastFromDIP(img.GetHeight()), //don't call fastFromDIP() from worker thread (wxWidgets function!)
- img.GetData(), img.GetAlpha() });
+ threadGroup_->run(getScalerTask(name, img, hqScale_, result_));
}
std::map<wxString, wxBitmap> waitAndGetResult()
{
- workload_.noMoreWork();
-
- for (InterruptibleThread& w : worker_)
- w.join();
+ threadGroup_->wait();
std::map<wxString, wxBitmap> output;
@@ -203,17 +129,20 @@ public:
wxImage img(ih.getWidth(), ih.getHeight(), ih.releaseRgb(), false /*static_data*/); //pass ownership
img.SetAlpha(ih.releaseAlpha(), false /*static_data*/);
- output[item.first] = wxBitmap(img);
+ output.emplace(item.first, std::move(img));
}
});
return output;
}
private:
- std::vector<InterruptibleThread> worker_;
- WorkLoad workload_;
- Protected<std::vector<std::pair<std::wstring, ImageHolder>>> result_;
+ const int hqScale_;
std::vector<wxImage> imgKeeper_;
+ Protected<std::vector<std::pair<std::wstring, ImageHolder>>> result_;
+
+ using TaskType = FunctionReturnTypeT<decltype(&getScalerTask)>;
+ Opt<ThreadGroup<TaskType>> threadGroup_{ ThreadGroup<TaskType>(std::max<int>(std::thread::hardware_concurrency(), 1), "xBRZ Scaler") };
+ //hardware_concurrency() == 0 if "not computable or well defined"
};
@@ -222,12 +151,12 @@ void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation& anim)
//work around wxWidgets bug:
//construct seekable input stream (zip-input stream is not seekable) for wxAnimation::Load()
//luckily this method call is very fast: below measurement precision!
- std::vector<char> data;
+ std::vector<std::byte> data;
data.reserve(10000);
int newValue = 0;
while ((newValue = zipInput.GetC()) != wxEOF)
- data.push_back(newValue);
+ data.push_back(static_cast<std::byte>(newValue));
wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data
@@ -243,7 +172,7 @@ public:
static std::shared_ptr<GlobalBitmaps> instance()
{
static Global<GlobalBitmaps> inst(std::make_unique<GlobalBitmaps>());
- assert(std::this_thread::get_id() == mainThreadId); //wxWidgets is not thread-safe!
+ assert(runningMainThread()); //wxWidgets is not thread-safe!
return inst.get();
}
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp
index 26a5b37c..88a78b21 100755
--- a/wx+/image_tools.cpp
+++ b/wx+/image_tools.cpp
@@ -83,7 +83,7 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
switch (align)
{
case ImageStackAlignment::CENTER:
- return (totalExtent - imageExtent) / 2;
+ return static_cast<int>(std::floor((totalExtent - imageExtent) / 2.0)); //consistency: round down negative values, too!
case ImageStackAlignment::LEFT:
return 0;
case ImageStackAlignment::RIGHT:
diff --git a/wx+/zlib_wrap.h b/wx+/zlib_wrap.h
index 7265331e..d3bb017b 100755
--- a/wx+/zlib_wrap.h
+++ b/wx+/zlib_wrap.h
@@ -52,8 +52,8 @@ BinContainer compress(const BinContainer& stream, int level) //throw ZlibInterna
//save uncompressed stream size for decompression
const uint64_t uncompressedSize = stream.size(); //use portable number type!
contOut.resize(sizeof(uncompressedSize));
- std::copy(reinterpret_cast<const char*>(&uncompressedSize),
- reinterpret_cast<const char*>(&uncompressedSize) + sizeof(uncompressedSize),
+ std::copy(reinterpret_cast<const std::byte*>(&uncompressedSize),
+ reinterpret_cast<const std::byte*>(&uncompressedSize) + sizeof(uncompressedSize),
&*contOut.begin());
const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!!
@@ -85,7 +85,7 @@ BinContainer decompress(const BinContainer& stream) //throw ZlibInternalError
throw ZlibInternalError();
std::copy(&*stream.begin(),
&*stream.begin() + sizeof(uncompressedSize),
- reinterpret_cast<char*>(&uncompressedSize));
+ reinterpret_cast<std::byte*>(&uncompressedSize));
//attention: contOut MUST NOT be empty! Else it will pass a nullptr to zlib_decompress() => Z_STREAM_ERROR although "uncompressedSize == 0"!!!
//secondary bug: don't dereference iterator into empty container!
if (uncompressedSize == 0) //cannot be 0: compress() directly maps empty -> empty container skipping zlib!
bgstack15