@@ -2,8 +2,8 @@ | |||||
set -e | set -e | ||||
JUCE_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/distrho/DISTRHO/libs/juce/source/modules/" | |||||
CARLA_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/falktx/Carla/source/modules/" | |||||
JUCE_MODULES_DIR="/home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO/libs/juce/source/modules/" | |||||
CARLA_MODULES_DIR="/home/falktx/FOSS/GIT-mine/Carla/source/modules/" | |||||
MODULES=("juce_audio_basics juce_audio_devices juce_audio_formats juce_audio_processors juce_core juce_data_structures juce_events juce_graphics juce_gui_basics juce_gui_extra") | MODULES=("juce_audio_basics juce_audio_devices juce_audio_formats juce_audio_processors juce_core juce_data_structures juce_events juce_graphics juce_gui_basics juce_gui_extra") | ||||
@@ -91,7 +91,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo, | |||||
allocatedBytes (0) | allocatedBytes (0) | ||||
{ | { | ||||
jassert (dataToReferTo != nullptr); | jassert (dataToReferTo != nullptr); | ||||
jassert (numChans >= 0); | |||||
jassert (numChans >= 0 && numSamples >= 0); | |||||
allocateChannels (dataToReferTo, 0); | allocateChannels (dataToReferTo, 0); | ||||
} | } | ||||
@@ -105,7 +105,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo, | |||||
isClear (false) | isClear (false) | ||||
{ | { | ||||
jassert (dataToReferTo != nullptr); | jassert (dataToReferTo != nullptr); | ||||
jassert (numChans >= 0); | |||||
jassert (numChans >= 0 && startSample >= 0 && numSamples >= 0); | |||||
allocateChannels (dataToReferTo, startSample); | allocateChannels (dataToReferTo, startSample); | ||||
} | } | ||||
@@ -114,7 +114,7 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, | |||||
const int newNumSamples) noexcept | const int newNumSamples) noexcept | ||||
{ | { | ||||
jassert (dataToReferTo != nullptr); | jassert (dataToReferTo != nullptr); | ||||
jassert (newNumChannels >= 0); | |||||
jassert (newNumChannels >= 0 && newNumSamples >= 0); | |||||
allocatedBytes = 0; | allocatedBytes = 0; | ||||
allocatedData.free(); | allocatedData.free(); | ||||
@@ -128,6 +128,8 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, | |||||
void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset) | void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset) | ||||
{ | { | ||||
jassert (offset >= 0); | |||||
// (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) | // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) | ||||
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) | if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) | ||||
{ | { | ||||
@@ -163,6 +165,8 @@ AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
isClear = false; | |||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
FloatVectorOperations::copy (channels[i], other.channels[i], size); | FloatVectorOperations::copy (channels[i], other.channels[i], size); | ||||
} | } | ||||
@@ -2233,10 +2233,11 @@ private: | |||||
#pragma warning (push) | #pragma warning (push) | ||||
#pragma warning (disable: 4244) | #pragma warning (disable: 4244) | ||||
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC); | |||||
if (! pluginWantsKeys) | if (! pluginWantsKeys) | ||||
{ | |||||
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC); | |||||
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc); | SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc); | ||||
} | |||||
#pragma warning (pop) | #pragma warning (pop) | ||||
@@ -2326,10 +2327,11 @@ private: | |||||
#if JUCE_WINDOWS | #if JUCE_WINDOWS | ||||
#pragma warning (push) | #pragma warning (push) | ||||
#pragma warning (disable: 4244) | #pragma warning (disable: 4244) | ||||
if (pluginHWND != 0 && IsWindow (pluginHWND)) | |||||
if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND)) | |||||
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc); | SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc); | ||||
#pragma warning (pop) | #pragma warning (pop) | ||||
originalWndProc = 0; | |||||
pluginHWND = 0; | pluginHWND = 0; | ||||
#elif JUCE_LINUX | #elif JUCE_LINUX | ||||
pluginWindow = 0; | pluginWindow = 0; | ||||
@@ -67,6 +67,8 @@ | |||||
#define JUCE_DISABLE_JUCE_VERSION_PRINTING 1 | #define JUCE_DISABLE_JUCE_VERSION_PRINTING 1 | ||||
#define JUCE_USE_VFORK 1 | |||||
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | ||||
#define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | ||||
#define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 | #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 | ||||
@@ -69,18 +69,16 @@ | |||||
#endif | #endif | ||||
#else | #else | ||||
#if JUCE_LINUX || JUCE_ANDROID | |||||
#if JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/errno.h> | |||||
#if ! JUCE_HAIKU | |||||
#include <sys/errno.h> | |||||
#endif | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#endif | #endif | ||||
#if JUCE_LINUX | |||||
#include <langinfo.h> | |||||
#endif | |||||
#include <pwd.h> | #include <pwd.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <netdb.h> | #include <netdb.h> | ||||
@@ -90,8 +88,9 @@ | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||
#if ! JUCE_ANDROID | |||||
#if JUCE_LINUX | |||||
#include <execinfo.h> | #include <execinfo.h> | ||||
#include <langinfo.h> | |||||
#endif | #endif | ||||
#endif | #endif | ||||
@@ -214,6 +213,10 @@ namespace juce | |||||
#include "native/juce_android_SystemStats.cpp" | #include "native/juce_android_SystemStats.cpp" | ||||
#include "native/juce_android_Threads.cpp" | #include "native/juce_android_Threads.cpp" | ||||
//============================================================================== | |||||
#elif JUCE_HAIKU | |||||
// TODO | |||||
#endif | #endif | ||||
#include "threads/juce_ChildProcess.cpp" | #include "threads/juce_ChildProcess.cpp" | ||||
@@ -129,6 +129,10 @@ | |||||
#define JUCE_STRING_UTF_TYPE 8 | #define JUCE_STRING_UTF_TYPE 8 | ||||
#endif | #endif | ||||
#ifndef JUCE_USE_VFORK | |||||
#define JUCE_USE_VFORK 0 | |||||
#endif | |||||
//============================================================================= | //============================================================================= | ||||
//============================================================================= | //============================================================================= | ||||
#if JUCE_MSVC | #if JUCE_MSVC | ||||
@@ -212,6 +212,33 @@ | |||||
#include <dirent.h> | #include <dirent.h> | ||||
#include <fnmatch.h> | #include <fnmatch.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
//============================================================================== | |||||
#elif JUCE_HAIKU | |||||
#include <sched.h> | |||||
#include <pthread.h> | |||||
#include <sys/time.h> | |||||
#include <errno.h> | |||||
#include <sys/stat.h> | |||||
#include <sys/statvfs.h> | |||||
#include <sys/wait.h> | |||||
#include <sys/mman.h> | |||||
#include <fnmatch.h> | |||||
#include <utime.h> | |||||
#include <pwd.h> | |||||
#include <fcntl.h> | |||||
#include <dlfcn.h> | |||||
#include <netdb.h> | |||||
#include <arpa/inet.h> | |||||
#include <netinet/in.h> | |||||
#include <sys/types.h> | |||||
#include <sys/ioctl.h> | |||||
#include <sys/socket.h> | |||||
#include <sys/sockio.h> | |||||
#include <net/if.h> | |||||
#include <sys/file.h> | |||||
#include <signal.h> | |||||
#include <stddef.h> | |||||
#endif | #endif | ||||
// Need to clear various moronic redefinitions made by system headers.. | // Need to clear various moronic redefinitions made by system headers.. | ||||
@@ -218,7 +218,11 @@ bool Process::openDocument (const String& fileName, const String& parameters) | |||||
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 }; | const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 }; | ||||
#if JUCE_USE_VFORK | |||||
const int cpid = vfork(); | const int cpid = vfork(); | ||||
#else | |||||
const int cpid = fork(); | |||||
#endif | |||||
if (cpid == 0) | if (cpid == 0) | ||||
{ | { | ||||
@@ -112,7 +112,11 @@ namespace FileHelpers | |||||
{ | { | ||||
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 }; | const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 }; | ||||
#if JUCE_USE_VFORK | |||||
const int cpid = vfork(); | const int cpid = vfork(); | ||||
#else | |||||
const int cpid = fork(); | |||||
#endif | |||||
if (cpid == 0) | if (cpid == 0) | ||||
{ | { | ||||
@@ -142,7 +142,7 @@ void JUCE_CALLTYPE Thread::sleep (int millisecs) | |||||
void JUCE_CALLTYPE Process::terminate() | void JUCE_CALLTYPE Process::terminate() | ||||
{ | { | ||||
#if JUCE_ANDROID | |||||
#if JUCE_ANDROID || JUCE_HAIKU | |||||
_exit (EXIT_FAILURE); | _exit (EXIT_FAILURE); | ||||
#else | #else | ||||
std::_Exit (EXIT_FAILURE); | std::_Exit (EXIT_FAILURE); | ||||
@@ -203,6 +203,10 @@ namespace | |||||
#define JUCE_STAT stat | #define JUCE_STAT stat | ||||
#endif | #endif | ||||
#if JUCE_HAIKU | |||||
#define statfs statvfs | |||||
#endif | |||||
bool juce_stat (const String& fileName, juce_statStruct& info) | bool juce_stat (const String& fileName, juce_statStruct& info) | ||||
{ | { | ||||
return fileName.isNotEmpty() | return fileName.isNotEmpty() | ||||
@@ -542,7 +546,11 @@ void MemoryMappedFile::openInternal (const File& file, AccessMode mode) | |||||
if (m != MAP_FAILED) | if (m != MAP_FAILED) | ||||
{ | { | ||||
address = m; | address = m; | ||||
madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL); | |||||
#if JUCE_HAIKU | |||||
posix_madvise (m, (size_t) range.getLength(), POSIX_MADV_SEQUENTIAL); | |||||
#else | |||||
madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL); | |||||
#endif | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -663,6 +671,10 @@ int File::getVolumeSerialNumber() const | |||||
return result; | return result; | ||||
} | } | ||||
#if JUCE_HAIKU | |||||
#undef statvfs | |||||
#endif | |||||
//============================================================================== | //============================================================================== | ||||
void juce_runSystemCommand (const String&); | void juce_runSystemCommand (const String&); | ||||
void juce_runSystemCommand (const String& command) | void juce_runSystemCommand (const String& command) | ||||
@@ -1006,16 +1018,20 @@ public: | |||||
int pipeHandles[2] = { 0 }; | int pipeHandles[2] = { 0 }; | ||||
if (pipe (pipeHandles) == 0) | |||||
{ | |||||
Array<char*> argv; | |||||
for (int i = 0; i < arguments.size(); ++i) | |||||
if (arguments[i].isNotEmpty()) | |||||
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress())); | |||||
Array<char*> argv; | |||||
for (int i = 0; i < arguments.size(); ++i) | |||||
if (arguments[i].isNotEmpty()) | |||||
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress())); | |||||
argv.add (nullptr); | |||||
argv.add (nullptr); | |||||
if (pipe (pipeHandles) == 0) | |||||
{ | |||||
#if JUCE_USE_VFORK | |||||
const pid_t result = vfork(); | const pid_t result = vfork(); | ||||
#else | |||||
const pid_t result = fork(); | |||||
#endif | |||||
if (result < 0) | if (result < 0) | ||||
{ | { | ||||
@@ -1024,7 +1040,7 @@ public: | |||||
} | } | ||||
else if (result == 0) | else if (result == 0) | ||||
{ | { | ||||
#if 0 | |||||
#if ! JUCE_USE_VFORK | |||||
// we're the child process.. | // we're the child process.. | ||||
close (pipeHandles[0]); // close the read handle | close (pipeHandles[0]); // close the read handle | ||||
@@ -1040,7 +1056,6 @@ public: | |||||
close (pipeHandles[1]); | close (pipeHandles[1]); | ||||
#endif | #endif | ||||
execvp (argv[0], argv.getRawDataPointer()); | execvp (argv[0], argv.getRawDataPointer()); | ||||
exit (-1); | exit (-1); | ||||
} | } | ||||
@@ -342,6 +342,7 @@ InputStream* URL::createInputStream (const bool usePostCommand, | |||||
if (! headers.endsWithChar ('\n')) | if (! headers.endsWithChar ('\n')) | ||||
headers << "\r\n"; | headers << "\r\n"; | ||||
#if ! JUCE_HAIKU | |||||
ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand), | ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand), | ||||
usePostCommand, headersAndPostData, | usePostCommand, headersAndPostData, | ||||
progressCallback, progressCallbackContext, | progressCallback, progressCallbackContext, | ||||
@@ -351,6 +352,9 @@ InputStream* URL::createInputStream (const bool usePostCommand, | |||||
*statusCode = wi->statusCode; | *statusCode = wi->statusCode; | ||||
return wi->isError() ? nullptr : wi.release(); | return wi->isError() ? nullptr : wi.release(); | ||||
#else | |||||
return nullptr; // TODO | |||||
#endif | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -97,7 +97,7 @@ String SystemStats::getStackBacktrace() | |||||
{ | { | ||||
String result; | String result; | ||||
#if JUCE_ANDROID || JUCE_MINGW | |||||
#if JUCE_ANDROID || JUCE_MINGW || JUCE_HAIKU | |||||
jassertfalse; // sorry, not implemented yet! | jassertfalse; // sorry, not implemented yet! | ||||
#elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
@@ -51,6 +51,8 @@ | |||||
#define JUCE_ANDROID 1 | #define JUCE_ANDROID 1 | ||||
#elif defined (LINUX) || defined (__linux__) | #elif defined (LINUX) || defined (__linux__) | ||||
#define JUCE_LINUX 1 | #define JUCE_LINUX 1 | ||||
#elif defined (__HAIKU__) | |||||
#define JUCE_HAIKU 1 | |||||
#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__) | #elif defined (__APPLE_CPP__) || defined(__APPLE_CC__) | ||||
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) | #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) | ||||
#define Component CarbonDummyCompName | #define Component CarbonDummyCompName | ||||
@@ -140,7 +142,7 @@ | |||||
#endif | #endif | ||||
//============================================================================== | //============================================================================== | ||||
#if JUCE_LINUX || JUCE_ANDROID | |||||
#if JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU | |||||
#ifdef _DEBUG | #ifdef _DEBUG | ||||
#define JUCE_DEBUG 1 | #define JUCE_DEBUG 1 | ||||
@@ -407,11 +407,11 @@ String Time::getWeekdayName (const bool threeLetterVersion) const | |||||
return getWeekdayName (getDayOfWeek(), threeLetterVersion); | return getWeekdayName (getDayOfWeek(), threeLetterVersion); | ||||
} | } | ||||
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |||||
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; | |||||
String Time::getMonthName (int monthNumber, const bool threeLetterVersion) | String Time::getMonthName (int monthNumber, const bool threeLetterVersion) | ||||
{ | { | ||||
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |||||
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; | |||||
monthNumber %= 12; | monthNumber %= 12; | ||||
return TRANS (threeLetterVersion ? shortMonthNames [monthNumber] | return TRANS (threeLetterVersion ? shortMonthNames [monthNumber] | ||||
@@ -430,17 +430,40 @@ String Time::getWeekdayName (int day, const bool threeLetterVersion) | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
Time& Time::operator+= (RelativeTime delta) { millisSinceEpoch += delta.inMilliseconds(); return *this; } | |||||
Time& Time::operator-= (RelativeTime delta) { millisSinceEpoch -= delta.inMilliseconds(); return *this; } | |||||
Time operator+ (Time time, RelativeTime delta) { Time t (time); return t += delta; } | |||||
Time operator- (Time time, RelativeTime delta) { Time t (time); return t -= delta; } | |||||
Time operator+ (RelativeTime delta, Time time) { Time t (time); return t += delta; } | |||||
const RelativeTime operator- (Time time1, Time time2) { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); } | |||||
bool operator== (Time time1, Time time2) { return time1.toMilliseconds() == time2.toMilliseconds(); } | |||||
bool operator!= (Time time1, Time time2) { return time1.toMilliseconds() != time2.toMilliseconds(); } | |||||
bool operator< (Time time1, Time time2) { return time1.toMilliseconds() < time2.toMilliseconds(); } | |||||
bool operator> (Time time1, Time time2) { return time1.toMilliseconds() > time2.toMilliseconds(); } | |||||
bool operator<= (Time time1, Time time2) { return time1.toMilliseconds() <= time2.toMilliseconds(); } | |||||
bool operator>= (Time time1, Time time2) { return time1.toMilliseconds() >= time2.toMilliseconds(); } | |||||
Time& Time::operator+= (RelativeTime delta) noexcept { millisSinceEpoch += delta.inMilliseconds(); return *this; } | |||||
Time& Time::operator-= (RelativeTime delta) noexcept { millisSinceEpoch -= delta.inMilliseconds(); return *this; } | |||||
Time operator+ (Time time, RelativeTime delta) noexcept { Time t (time); return t += delta; } | |||||
Time operator- (Time time, RelativeTime delta) noexcept { Time t (time); return t -= delta; } | |||||
Time operator+ (RelativeTime delta, Time time) noexcept { Time t (time); return t += delta; } | |||||
const RelativeTime operator- (Time time1, Time time2) noexcept { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); } | |||||
bool operator== (Time time1, Time time2) noexcept { return time1.toMilliseconds() == time2.toMilliseconds(); } | |||||
bool operator!= (Time time1, Time time2) noexcept { return time1.toMilliseconds() != time2.toMilliseconds(); } | |||||
bool operator< (Time time1, Time time2) noexcept { return time1.toMilliseconds() < time2.toMilliseconds(); } | |||||
bool operator> (Time time1, Time time2) noexcept { return time1.toMilliseconds() > time2.toMilliseconds(); } | |||||
bool operator<= (Time time1, Time time2) noexcept { return time1.toMilliseconds() <= time2.toMilliseconds(); } | |||||
bool operator>= (Time time1, Time time2) noexcept { return time1.toMilliseconds() >= time2.toMilliseconds(); } | |||||
static int getMonthNumberForCompileDate (const String& m) noexcept | |||||
{ | |||||
for (int i = 0; i < 12; ++i) | |||||
if (m.equalsIgnoreCase (shortMonthNames[i])) | |||||
return i; | |||||
// If you hit this because your compiler has a non-standard __DATE__ format, | |||||
// let me know so we can add support for it! | |||||
jassertfalse; | |||||
return 0; | |||||
} | |||||
Time Time::getCompilationDate() | |||||
{ | |||||
StringArray dateTokens; | |||||
dateTokens.addTokens (__DATE__, true); | |||||
dateTokens.removeEmptyStrings (true); | |||||
return Time (dateTokens[2].getIntValue(), | |||||
getMonthNumberForCompileDate (dateTokens[0]), | |||||
dateTokens[1].getIntValue(), 12, 0); | |||||
} |
@@ -253,9 +253,9 @@ public: | |||||
//============================================================================== | //============================================================================== | ||||
/** Adds a RelativeTime to this time. */ | /** Adds a RelativeTime to this time. */ | ||||
Time& operator+= (RelativeTime delta); | |||||
Time& operator+= (RelativeTime delta) noexcept; | |||||
/** Subtracts a RelativeTime from this time. */ | /** Subtracts a RelativeTime from this time. */ | ||||
Time& operator-= (RelativeTime delta); | |||||
Time& operator-= (RelativeTime delta) noexcept; | |||||
//============================================================================== | //============================================================================== | ||||
/** Tries to set the computer's clock. | /** Tries to set the computer's clock. | ||||
@@ -272,8 +272,7 @@ public: | |||||
@param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if | @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if | ||||
false, it'll return the full version, e.g. "Tuesday". | false, it'll return the full version, e.g. "Tuesday". | ||||
*/ | */ | ||||
static String getWeekdayName (int dayNumber, | |||||
bool threeLetterVersion); | |||||
static String getWeekdayName (int dayNumber, bool threeLetterVersion); | |||||
/** Returns the name of one of the months. | /** Returns the name of one of the months. | ||||
@@ -281,8 +280,7 @@ public: | |||||
@param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false | @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false | ||||
it'll return the long form, e.g. "January" | it'll return the long form, e.g. "January" | ||||
*/ | */ | ||||
static String getMonthName (int monthNumber, | |||||
bool threeLetterVersion); | |||||
static String getMonthName (int monthNumber, bool threeLetterVersion); | |||||
//============================================================================== | //============================================================================== | ||||
// Static methods for getting system timers directly.. | // Static methods for getting system timers directly.. | ||||
@@ -370,6 +368,8 @@ public: | |||||
*/ | */ | ||||
static int64 secondsToHighResolutionTicks (double seconds) noexcept; | static int64 secondsToHighResolutionTicks (double seconds) noexcept; | ||||
/** Returns a Time based on the value of the __DATE__ macro when this module was compiled */ | |||||
static Time getCompilationDate(); | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
@@ -378,27 +378,27 @@ private: | |||||
//============================================================================== | //============================================================================== | ||||
/** Adds a RelativeTime to a Time. */ | /** Adds a RelativeTime to a Time. */ | ||||
JUCE_API Time operator+ (Time time, RelativeTime delta); | |||||
JUCE_API Time operator+ (Time time, RelativeTime delta) noexcept; | |||||
/** Adds a RelativeTime to a Time. */ | /** Adds a RelativeTime to a Time. */ | ||||
JUCE_API Time operator+ (RelativeTime delta, Time time); | |||||
JUCE_API Time operator+ (RelativeTime delta, Time time) noexcept; | |||||
/** Subtracts a RelativeTime from a Time. */ | /** Subtracts a RelativeTime from a Time. */ | ||||
JUCE_API Time operator- (Time time, RelativeTime delta); | |||||
JUCE_API Time operator- (Time time, RelativeTime delta) noexcept; | |||||
/** Returns the relative time difference between two times. */ | /** Returns the relative time difference between two times. */ | ||||
JUCE_API const RelativeTime operator- (Time time1, Time time2); | |||||
JUCE_API const RelativeTime operator- (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator== (Time time1, Time time2); | |||||
JUCE_API bool operator== (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator!= (Time time1, Time time2); | |||||
JUCE_API bool operator!= (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator< (Time time1, Time time2); | |||||
JUCE_API bool operator< (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator<= (Time time1, Time time2); | |||||
JUCE_API bool operator<= (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator> (Time time1, Time time2); | |||||
JUCE_API bool operator> (Time time1, Time time2) noexcept; | |||||
/** Compares two Time objects. */ | /** Compares two Time objects. */ | ||||
JUCE_API bool operator>= (Time time1, Time time2); | |||||
JUCE_API bool operator>= (Time time1, Time time2) noexcept; | |||||
#endif // JUCE_TIME_H_INCLUDED | #endif // JUCE_TIME_H_INCLUDED |
@@ -298,8 +298,7 @@ InputStream* ZipFile::createStreamForEntry (const int index) | |||||
if (zei->compressed) | if (zei->compressed) | ||||
{ | { | ||||
stream = new GZIPDecompressorInputStream (stream, true, true, | |||||
zei->entry.uncompressedSize); | |||||
stream = new GZIPDecompressorInputStream (stream, true, true, (int64) zei->entry.uncompressedSize); | |||||
// (much faster to unzip in big blocks using a buffer..) | // (much faster to unzip in big blocks using a buffer..) | ||||
stream = new BufferedInputStream (stream, 32768, true); | stream = new BufferedInputStream (stream, 32768, true); | ||||
@@ -82,7 +82,7 @@ File PropertiesFile::Options::getDefaultFile() const | |||||
if (folderName.isNotEmpty()) | if (folderName.isNotEmpty()) | ||||
dir = dir.getChildFile (folderName); | dir = dir.getChildFile (folderName); | ||||
#elif JUCE_LINUX || JUCE_ANDROID | |||||
#elif JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU | |||||
const File dir (File (commonToAllUsers ? "/var" : "~") | const File dir (File (commonToAllUsers ? "/var" : "~") | ||||
.getChildFile (folderName.isNotEmpty() ? folderName | .getChildFile (folderName.isNotEmpty() ? folderName | ||||
: ("." + applicationName))); | : ("." + applicationName))); | ||||
@@ -358,8 +358,13 @@ bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* cons | |||||
if (LinuxErrorHandling::errorOccurred) | if (LinuxErrorHandling::errorOccurred) | ||||
return false; | return false; | ||||
InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message); | |||||
return true; | |||||
if (InternalMessageQueue* const queue = InternalMessageQueue::getInstanceWithoutCreating()) | |||||
{ | |||||
InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
void MessageManager::broadcastMessage (const String& /* value */) | void MessageManager::broadcastMessage (const String& /* value */) | ||||
@@ -278,13 +278,13 @@ Font& Font::operator= (const Font& other) noexcept | |||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
Font::Font (Font&& other) noexcept | Font::Font (Font&& other) noexcept | ||||
: font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font)) | |||||
: font (static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font)) | |||||
{ | { | ||||
} | } | ||||
Font& Font::operator= (Font&& other) noexcept | Font& Font::operator= (Font&& other) noexcept | ||||
{ | { | ||||
font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font); | |||||
font = static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font); | |||||
return *this; | return *this; | ||||
} | } | ||||
#endif | #endif | ||||
@@ -640,7 +640,7 @@ float Font::getStringWidthFloat (const String& text) const | |||||
return w * font->height * font->horizontalScale; | return w * font->height * font->horizontalScale; | ||||
} | } | ||||
void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const | |||||
void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const | |||||
{ | { | ||||
getTypeface()->getGlyphPositions (text, glyphs, xOffsets); | getTypeface()->getGlyphPositions (text, glyphs, xOffsets); | ||||
@@ -449,7 +449,7 @@ public: | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
class SharedFontInternal; | class SharedFontInternal; | ||||
ReferenceCountedObjectPtr <SharedFontInternal> font; | |||||
ReferenceCountedObjectPtr<SharedFontInternal> font; | |||||
void dupeInternalIfShared(); | void dupeInternalIfShared(); | ||||
void checkTypefaceSuitability(); | void checkTypefaceSuitability(); | ||||
float getHeightToPointsFactor() const; | float getHeightToPointsFactor() const; | ||||
@@ -40,6 +40,27 @@ PositionedGlyph::PositionedGlyph (const PositionedGlyph& other) | |||||
{ | { | ||||
} | } | ||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
PositionedGlyph::PositionedGlyph (PositionedGlyph&& other) noexcept | |||||
: font (static_cast<Font&&> (other.font)), | |||||
character (other.character), glyph (other.glyph), | |||||
x (other.x), y (other.y), w (other.w), whitespace (other.whitespace) | |||||
{ | |||||
} | |||||
PositionedGlyph& PositionedGlyph::operator= (PositionedGlyph&& other) noexcept | |||||
{ | |||||
font = static_cast<Font&&> (other.font); | |||||
character = other.character; | |||||
glyph = other.glyph; | |||||
x = other.x; | |||||
y = other.y; | |||||
w = other.w; | |||||
whitespace = other.whitespace; | |||||
return *this; | |||||
} | |||||
#endif | |||||
PositionedGlyph::~PositionedGlyph() {} | PositionedGlyph::~PositionedGlyph() {} | ||||
PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other) | PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other) | ||||
@@ -182,8 +203,8 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||||
{ | { | ||||
if (text.isNotEmpty()) | if (text.isNotEmpty()) | ||||
{ | { | ||||
Array <int> newGlyphs; | |||||
Array <float> xOffsets; | |||||
Array<int> newGlyphs; | |||||
Array<float> xOffsets; | |||||
font.getGlyphPositions (text, newGlyphs, xOffsets); | font.getGlyphPositions (text, newGlyphs, xOffsets); | ||||
const int textLen = newGlyphs.size(); | const int textLen = newGlyphs.size(); | ||||
glyphs.ensureStorageAllocated (glyphs.size() + textLen); | glyphs.ensureStorageAllocated (glyphs.size() + textLen); | ||||
@@ -353,174 +374,40 @@ void GlyphArrangement::addFittedText (const Font& f, | |||||
if (text.containsAnyOf ("\r\n")) | if (text.containsAnyOf ("\r\n")) | ||||
{ | { | ||||
GlyphArrangement ga; | |||||
ga.addJustifiedText (f, text, x, y, width, layout); | |||||
const Rectangle<float> bb (ga.getBoundingBox (0, -1, false)); | |||||
float dy = y - bb.getY(); | |||||
if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f; | |||||
else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight()); | |||||
ga.moveRangeOfGlyphs (0, -1, 0.0f, dy); | |||||
glyphs.addArray (ga.glyphs); | |||||
return; | |||||
addLinesWithLineBreaks (text, f, x, y, width, height, layout); | |||||
} | } | ||||
int startIndex = glyphs.size(); | |||||
addLineOfText (f, text.trim(), x, y); | |||||
if (glyphs.size() > startIndex) | |||||
else | |||||
{ | { | ||||
float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||||
- glyphs.getReference (startIndex).getLeft(); | |||||
const int startIndex = glyphs.size(); | |||||
const String trimmed (text.trim()); | |||||
addLineOfText (f, trimmed, x, y); | |||||
const int numGlyphs = glyphs.size() - startIndex; | |||||
if (lineWidth <= 0) | |||||
return; | |||||
if (lineWidth * minimumHorizontalScale < width) | |||||
{ | |||||
if (lineWidth > width) | |||||
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex, | |||||
width / lineWidth); | |||||
justifyGlyphs (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, layout); | |||||
} | |||||
else if (maximumLines <= 1) | |||||
{ | |||||
fitLineIntoSpace (startIndex, glyphs.size() - startIndex, | |||||
x, y, width, height, f, layout, minimumHorizontalScale); | |||||
} | |||||
else | |||||
if (numGlyphs > 0) | |||||
{ | { | ||||
Font font (f); | |||||
String txt (text.trim()); | |||||
const int length = txt.length(); | |||||
const int originalStartIndex = startIndex; | |||||
int numLines = 1; | |||||
if (length <= 12 && ! txt.containsAnyOf (" -\t\r\n")) | |||||
maximumLines = 1; | |||||
maximumLines = jmin (maximumLines, length); | |||||
const float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||||
- glyphs.getReference (startIndex).getLeft(); | |||||
while (numLines < maximumLines) | |||||
if (lineWidth > 0) | |||||
{ | { | ||||
++numLines; | |||||
const float newFontHeight = height / (float) numLines; | |||||
if (newFontHeight < font.getHeight()) | |||||
if (lineWidth * minimumHorizontalScale < width) | |||||
{ | { | ||||
font.setHeight (jmax (8.0f, newFontHeight)); | |||||
if (lineWidth > width) | |||||
stretchRangeOfGlyphs (startIndex, numGlyphs, width / lineWidth); | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
addLineOfText (font, txt, x, y); | |||||
lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||||
- glyphs.getReference (startIndex).getLeft(); | |||||
justifyGlyphs (startIndex, numGlyphs, x, y, width, height, layout); | |||||
} | } | ||||
if (numLines > lineWidth / width || newFontHeight < 8.0f) | |||||
break; | |||||
} | |||||
if (numLines < 1) | |||||
numLines = 1; | |||||
float lineY = y; | |||||
float widthPerLine = lineWidth / numLines; | |||||
for (int line = 0; line < numLines; ++line) | |||||
{ | |||||
int i = startIndex; | |||||
float lineStartX = glyphs.getReference (startIndex).getLeft(); | |||||
if (line == numLines - 1) | |||||
else if (maximumLines <= 1) | |||||
{ | { | ||||
widthPerLine = width; | |||||
i = glyphs.size(); | |||||
fitLineIntoSpace (startIndex, numGlyphs, x, y, width, height, | |||||
f, layout, minimumHorizontalScale); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
while (i < glyphs.size()) | |||||
{ | |||||
lineWidth = (glyphs.getReference (i).getRight() - lineStartX); | |||||
if (lineWidth > widthPerLine) | |||||
{ | |||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
while (i < glyphs.size()) | |||||
{ | |||||
if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
{ | |||||
if (glyphs.getReference (i).isWhitespace() | |||||
|| glyphs.getReference (i).getCharacter() == '-') | |||||
{ | |||||
++i; | |||||
break; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (7, i - startIndex - 1); ++back) | |||||
{ | |||||
if (glyphs.getReference (i - back).isWhitespace() | |||||
|| glyphs.getReference (i - back).getCharacter() == '-') | |||||
{ | |||||
i -= back - 1; | |||||
break; | |||||
} | |||||
} | |||||
break; | |||||
} | |||||
++i; | |||||
} | |||||
break; | |||||
} | |||||
++i; | |||||
} | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace()) | |||||
--wsStart; | |||||
int wsEnd = i; | |||||
while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace()) | |||||
++wsEnd; | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
splitLines (trimmed, f, startIndex, x, y, width, height, | |||||
maximumLines, lineWidth, layout, minimumHorizontalScale); | |||||
} | } | ||||
i -= fitLineIntoSpace (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), font, | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred, | |||||
minimumHorizontalScale); | |||||
startIndex = i; | |||||
lineY += font.getHeight(); | |||||
if (startIndex >= glyphs.size()) | |||||
break; | |||||
} | } | ||||
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex, | |||||
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -540,6 +427,24 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float d | |||||
} | } | ||||
} | } | ||||
void GlyphArrangement::addLinesWithLineBreaks (const String& text, const Font& f, | |||||
int x, int y, int width, int height, Justification layout) | |||||
{ | |||||
GlyphArrangement ga; | |||||
ga.addJustifiedText (f, text, x, y, width, layout); | |||||
const Rectangle<float> bb (ga.getBoundingBox (0, -1, false)); | |||||
float dy = y - bb.getY(); | |||||
if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f; | |||||
else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight()); | |||||
ga.moveRangeOfGlyphs (0, -1, 0.0f, dy); | |||||
glyphs.addArray (ga.glyphs); | |||||
} | |||||
int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | ||||
Justification justification, float minimumHorizontalScale) | Justification justification, float minimumHorizontalScale) | ||||
{ | { | ||||
@@ -702,9 +607,142 @@ void GlyphArrangement::spreadOutLine (const int start, const int num, const floa | |||||
} | } | ||||
} | } | ||||
void GlyphArrangement::splitLines (const String& text, Font font, int startIndex, | |||||
int x, int y, int width, int height, int maximumLines, | |||||
float lineWidth, Justification layout, float minimumHorizontalScale) | |||||
{ | |||||
const int length = text.length(); | |||||
const int originalStartIndex = startIndex; | |||||
int numLines = 1; | |||||
if (length <= 12 && ! text.containsAnyOf (" -\t\r\n")) | |||||
maximumLines = 1; | |||||
maximumLines = jmin (maximumLines, length); | |||||
while (numLines < maximumLines) | |||||
{ | |||||
++numLines; | |||||
const float newFontHeight = height / (float) numLines; | |||||
if (newFontHeight < font.getHeight()) | |||||
{ | |||||
font.setHeight (jmax (8.0f, newFontHeight)); | |||||
removeRangeOfGlyphs (startIndex, -1); | |||||
addLineOfText (font, text, x, y); | |||||
lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() | |||||
- glyphs.getReference (startIndex).getLeft(); | |||||
} | |||||
// Try to estimate the point at which there are enough lines to fit the text, | |||||
// allowing for unevenness in the lengths due to differently sized words. | |||||
const float lineLengthUnevennessAllowance = 80.0f; | |||||
if (numLines > (lineWidth + lineLengthUnevennessAllowance) / width || newFontHeight < 8.0f) | |||||
break; | |||||
} | |||||
if (numLines < 1) | |||||
numLines = 1; | |||||
float lineY = y; | |||||
float widthPerLine = lineWidth / numLines; | |||||
for (int line = 0; line < numLines; ++line) | |||||
{ | |||||
int i = startIndex; | |||||
float lineStartX = glyphs.getReference (startIndex).getLeft(); | |||||
if (line == numLines - 1) | |||||
{ | |||||
widthPerLine = width; | |||||
i = glyphs.size(); | |||||
} | |||||
else | |||||
{ | |||||
while (i < glyphs.size()) | |||||
{ | |||||
lineWidth = (glyphs.getReference (i).getRight() - lineStartX); | |||||
if (lineWidth > widthPerLine) | |||||
{ | |||||
// got to a point where the line's too long, so skip forward to find a | |||||
// good place to break it.. | |||||
const int searchStartIndex = i; | |||||
while (i < glyphs.size()) | |||||
{ | |||||
if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width) | |||||
{ | |||||
if (glyphs.getReference (i).isWhitespace() | |||||
|| glyphs.getReference (i).getCharacter() == '-') | |||||
{ | |||||
++i; | |||||
break; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
// can't find a suitable break, so try looking backwards.. | |||||
i = searchStartIndex; | |||||
for (int back = 1; back < jmin (7, i - startIndex - 1); ++back) | |||||
{ | |||||
if (glyphs.getReference (i - back).isWhitespace() | |||||
|| glyphs.getReference (i - back).getCharacter() == '-') | |||||
{ | |||||
i -= back - 1; | |||||
break; | |||||
} | |||||
} | |||||
break; | |||||
} | |||||
++i; | |||||
} | |||||
break; | |||||
} | |||||
++i; | |||||
} | |||||
int wsStart = i; | |||||
while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace()) | |||||
--wsStart; | |||||
int wsEnd = i; | |||||
while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace()) | |||||
++wsEnd; | |||||
removeRangeOfGlyphs (wsStart, wsEnd - wsStart); | |||||
i = jmax (wsStart, startIndex + 1); | |||||
} | |||||
i -= fitLineIntoSpace (startIndex, i - startIndex, | |||||
x, lineY, width, font.getHeight(), font, | |||||
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred, | |||||
minimumHorizontalScale); | |||||
startIndex = i; | |||||
lineY += font.getHeight(); | |||||
if (startIndex >= glyphs.size()) | |||||
break; | |||||
} | |||||
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex, | |||||
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
inline void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGlyph& pg, | |||||
const int i, const AffineTransform& transform) const | |||||
void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGlyph& pg, | |||||
const int i, const AffineTransform& transform) const | |||||
{ | { | ||||
const float lineThickness = (pg.font.getDescent()) * 0.3f; | const float lineThickness = (pg.font.getDescent()) * 0.3f; | ||||
@@ -46,6 +46,12 @@ public: | |||||
PositionedGlyph (const PositionedGlyph&); | PositionedGlyph (const PositionedGlyph&); | ||||
PositionedGlyph& operator= (const PositionedGlyph&); | PositionedGlyph& operator= (const PositionedGlyph&); | ||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
PositionedGlyph (PositionedGlyph&&) noexcept; | |||||
PositionedGlyph& operator= (PositionedGlyph&&) noexcept; | |||||
#endif | |||||
~PositionedGlyph(); | ~PositionedGlyph(); | ||||
/** Returns the character the glyph represents. */ | /** Returns the character the glyph represents. */ | ||||
@@ -295,12 +301,15 @@ public: | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
Array <PositionedGlyph> glyphs; | |||||
Array<PositionedGlyph> glyphs; | |||||
int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex); | int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex); | ||||
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&, | int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&, | ||||
Justification, float minimumHorizontalScale); | Justification, float minimumHorizontalScale); | ||||
void spreadOutLine (int start, int numGlyphs, float targetWidth); | void spreadOutLine (int start, int numGlyphs, float targetWidth); | ||||
void splitLines (const String&, Font, int start, int x, int y, int w, int h, int maxLines, | |||||
float lineWidth, Justification, float minimumHorizontalScale); | |||||
void addLinesWithLineBreaks (const String&, const Font&, int x, int y, int width, int height, Justification); | |||||
void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, const AffineTransform&) const; | void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, const AffineTransform&) const; | ||||
JUCE_LEAK_DETECTOR (GlyphArrangement) | JUCE_LEAK_DETECTOR (GlyphArrangement) | ||||
@@ -628,6 +628,17 @@ public: | |||||
/** Standard method for iterating the rectangles in the list. */ | /** Standard method for iterating the rectangles in the list. */ | ||||
const RectangleType* end() const noexcept { return rects.end(); } | const RectangleType* end() const noexcept { return rects.end(); } | ||||
/** Increases the internal storage to hold a minimum number of rectangles. | |||||
Calling this before adding a large number of rectangles means that | |||||
the array won't have to keep dynamically resizing itself as the elements | |||||
are added, and it'll therefore be more efficient. | |||||
@see Array::ensureStorageAllocated | |||||
*/ | |||||
void ensureStorageAllocated (int minNumRectangles) | |||||
{ | |||||
rects.ensureStorageAllocated (minNumRectangles); | |||||
} | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
Array<RectangleType> rects; | Array<RectangleType> rects; | ||||
@@ -29,8 +29,9 @@ namespace DirectWriteTypeLayout | |||||
class CustomDirectWriteTextRenderer : public ComBaseClassHelper<IDWriteTextRenderer> | class CustomDirectWriteTextRenderer : public ComBaseClassHelper<IDWriteTextRenderer> | ||||
{ | { | ||||
public: | public: | ||||
CustomDirectWriteTextRenderer (IDWriteFontCollection* const fonts) | |||||
CustomDirectWriteTextRenderer (IDWriteFontCollection* const fonts, const AttributedString& as) | |||||
: ComBaseClassHelper<IDWriteTextRenderer> (0), | : ComBaseClassHelper<IDWriteTextRenderer> (0), | ||||
attributedString (as), | |||||
fontCollection (fonts), | fontCollection (fonts), | ||||
currentLine (-1), | currentLine (-1), | ||||
lastOriginY (-10000.0f) | lastOriginY (-10000.0f) | ||||
@@ -89,20 +90,16 @@ namespace DirectWriteTypeLayout | |||||
glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, glyphRun)); | glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, glyphRun)); | ||||
glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun)); | glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun)); | ||||
String fontFamily, fontStyle; | |||||
getFontFamilyAndStyle (glyphRun, fontFamily, fontStyle); | |||||
TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition, | TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition, | ||||
runDescription->textPosition + runDescription->stringLength), | runDescription->textPosition + runDescription->stringLength), | ||||
glyphRun->glyphCount); | glyphRun->glyphCount); | ||||
glyphLine.runs.add (glyphRunLayout); | glyphLine.runs.add (glyphRunLayout); | ||||
glyphRun->fontFace->GetMetrics (&dwFontMetrics); | glyphRun->fontFace->GetMetrics (&dwFontMetrics); | ||||
const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); | const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); | ||||
const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; | const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; | ||||
glyphRunLayout->font = Font (fontFamily, fontStyle, glyphRun->fontEmSize / fontHeightToEmSizeFactor); | |||||
glyphRunLayout->font = getFontForRun (glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor); | |||||
glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect)); | glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect)); | ||||
const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin); | const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin); | ||||
@@ -127,6 +124,7 @@ namespace DirectWriteTypeLayout | |||||
} | } | ||||
private: | private: | ||||
const AttributedString& attributedString; | |||||
IDWriteFontCollection* const fontCollection; | IDWriteFontCollection* const fontCollection; | ||||
int currentLine; | int currentLine; | ||||
float lastOriginY; | float lastOriginY; | ||||
@@ -145,19 +143,22 @@ namespace DirectWriteTypeLayout | |||||
return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a); | return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a); | ||||
} | } | ||||
void getFontFamilyAndStyle (DWRITE_GLYPH_RUN const* glyphRun, String& family, String& style) const | |||||
Font getFontForRun (DWRITE_GLYPH_RUN const* glyphRun, float fontHeight) | |||||
{ | { | ||||
for (int i = 0; i < attributedString.getNumAttributes(); ++i) | |||||
if (const Font* font = attributedString.getAttribute(i)->getFont()) | |||||
if (WindowsDirectWriteTypeface* wt = dynamic_cast<WindowsDirectWriteTypeface*> (font->getTypeface())) | |||||
if (wt->getIDWriteFontFace() == glyphRun->fontFace) | |||||
return font->withHeight (fontHeight); | |||||
ComSmartPtr<IDWriteFont> dwFont; | ComSmartPtr<IDWriteFont> dwFont; | ||||
HRESULT hr = fontCollection->GetFontFromFontFace (glyphRun->fontFace, dwFont.resetAndGetPointerAddress()); | HRESULT hr = fontCollection->GetFontFromFontFace (glyphRun->fontFace, dwFont.resetAndGetPointerAddress()); | ||||
jassert (dwFont != nullptr); | jassert (dwFont != nullptr); | ||||
{ | |||||
ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||||
hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress()); | |||||
family = getFontFamilyName (dwFontFamily); | |||||
} | |||||
ComSmartPtr<IDWriteFontFamily> dwFontFamily; | |||||
hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress()); | |||||
style = getFontFaceName (dwFont); | |||||
return Font (getFontFamilyName (dwFontFamily), getFontFaceName (dwFont), fontHeight); | |||||
} | } | ||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomDirectWriteTextRenderer) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomDirectWriteTextRenderer) | ||||
@@ -352,11 +353,11 @@ namespace DirectWriteTypeLayout | |||||
layout.ensureStorageAllocated (actualLineCount); | layout.ensureStorageAllocated (actualLineCount); | ||||
{ | { | ||||
ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection)); | |||||
ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text)); | |||||
hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); | hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); | ||||
} | } | ||||
HeapBlock <DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount); | |||||
HeapBlock<DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount); | |||||
hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount); | hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount); | ||||
int lastLocation = 0; | int lastLocation = 0; | ||||
const int numLines = jmin ((int) actualLineCount, layout.getNumLines()); | const int numLines = jmin ((int) actualLineCount, layout.getNumLines()); | ||||
@@ -384,11 +385,27 @@ namespace DirectWriteTypeLayout | |||||
} | } | ||||
} | } | ||||
} | } | ||||
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text) | |||||
{ | |||||
const int numCharacterAttributes = text.getNumAttributes(); | |||||
for (int i = 0; i < numCharacterAttributes; ++i) | |||||
if (const Font* const font = text.getAttribute (i)->getFont()) | |||||
if (dynamic_cast<WindowsDirectWriteTypeface*> (font->getTypeface()) == nullptr) | |||||
return false; | |||||
return true; | |||||
} | |||||
#endif | #endif | ||||
bool TextLayout::createNativeLayout (const AttributedString& text) | bool TextLayout::createNativeLayout (const AttributedString& text) | ||||
{ | { | ||||
#if JUCE_USE_DIRECTWRITE | #if JUCE_USE_DIRECTWRITE | ||||
if (! canAllTypefacesBeUsedInLayout (text)) | |||||
return false; | |||||
SharedResourcePointer<Direct2DFactories> factories; | SharedResourcePointer<Direct2DFactories> factories; | ||||
if (factories->d2dFactory != nullptr && factories->systemFonts != nullptr) | if (factories->d2dFactory != nullptr && factories->systemFonts != nullptr) | ||||
@@ -139,26 +139,26 @@ public: | |||||
hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); | hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); | ||||
// Get a specific font in the font family using typeface style | // Get a specific font in the font family using typeface style | ||||
ComSmartPtr<IDWriteFont> dwFont; | |||||
uint32 fontFacesCount = 0; | |||||
fontFacesCount = dwFontFamily->GetFontCount(); | |||||
for (int i = fontFacesCount; --i >= 0;) | |||||
{ | { | ||||
hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); | |||||
ComSmartPtr<IDWriteFont> dwFont; | |||||
if (i == 0) | |||||
break; | |||||
for (int i = (int) dwFontFamily->GetFontCount(); --i >= 0;) | |||||
{ | |||||
hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); | |||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames; | |||||
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress()); | |||||
if (i == 0) | |||||
break; | |||||
if (font.getTypefaceStyle() == getLocalisedName (faceNames)) | |||||
break; | |||||
} | |||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames; | |||||
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress()); | |||||
jassert (dwFont != nullptr); | |||||
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); | |||||
if (font.getTypefaceStyle() == getLocalisedName (faceNames)) | |||||
break; | |||||
} | |||||
jassert (dwFont != nullptr); | |||||
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); | |||||
} | |||||
if (dwFontFace != nullptr) | if (dwFontFace != nullptr) | ||||
{ | { | ||||
@@ -162,9 +162,14 @@ void FilenameComponent::fileDragExit (const StringArray&) | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
String FilenameComponent::getCurrentFileText() const | |||||
{ | |||||
return filenameBox.getText(); | |||||
} | |||||
File FilenameComponent::getCurrentFile() const | File FilenameComponent::getCurrentFile() const | ||||
{ | { | ||||
File f (File::getCurrentWorkingDirectory().getChildFile (filenameBox.getText())); | |||||
File f (File::getCurrentWorkingDirectory().getChildFile (getCurrentFileText())); | |||||
if (enforcedSuffix.isNotEmpty()) | if (enforcedSuffix.isNotEmpty()) | ||||
f = f.withFileExtension (enforcedSuffix); | f = f.withFileExtension (enforcedSuffix); | ||||
@@ -103,6 +103,9 @@ public: | |||||
/** Returns the currently displayed filename. */ | /** Returns the currently displayed filename. */ | ||||
File getCurrentFile() const; | File getCurrentFile() const; | ||||
/** Returns the raw text that the user has entered. */ | |||||
String getCurrentFileText() const; | |||||
/** Changes the current filename. | /** Changes the current filename. | ||||
@param newFile the new filename to use | @param newFile the new filename to use | ||||
@@ -1222,6 +1222,8 @@ private: | |||||
const Rectangle<int> clipBounds (clipW, clipH); | const Rectangle<int> clipBounds (clipW, clipH); | ||||
const CGFloat viewH = [view frame].size.height; | const CGFloat viewH = [view frame].size.height; | ||||
clip.ensureStorageAllocated ((int) numRects); | |||||
for (int i = 0; i < numRects; ++i) | for (int i = 0; i < numRects; ++i) | ||||
clip.addWithoutMerging (clipBounds.getIntersection (Rectangle<int> (roundToInt (rects[i].origin.x) + offset.x, | clip.addWithoutMerging (clipBounds.getIntersection (Rectangle<int> (roundToInt (rects[i].origin.x) + offset.x, | ||||
roundToInt (viewH - (rects[i].origin.y + rects[i].size.height)) + offset.y, | roundToInt (viewH - (rects[i].origin.y + rects[i].size.height)) + offset.y, | ||||
@@ -53,7 +53,10 @@ public: | |||||
~Pimpl() | ~Pimpl() | ||||
{ | { | ||||
[[NSNotificationCenter defaultCenter] removeObserver: view]; | |||||
[[NSStatusBar systemStatusBar] removeStatusItem: statusItem]; | [[NSStatusBar systemStatusBar] removeStatusItem: statusItem]; | ||||
SystemTrayViewClass::setOwner (view, nullptr); | |||||
SystemTrayViewClass::setImage (view, nil); | |||||
[statusItem release]; | [statusItem release]; | ||||
[view release]; | [view release]; | ||||
[statusIcon release]; | [statusIcon release]; | ||||