| @@ -10068,6 +10068,7 @@ private: | |||||
| void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); | void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); | ||||
| void clipEdgeTableLineToRange (int* line, int x1, int x2) throw(); | void clipEdgeTableLineToRange (int* line, int x1, int x2) throw(); | ||||
| void sanitiseLevels (const bool useNonZeroWinding) throw(); | void sanitiseLevels (const bool useNonZeroWinding) throw(); | ||||
| static void copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) throw(); | |||||
| }; | }; | ||||
| #endif // __JUCE_EDGETABLE_JUCEHEADER__ | #endif // __JUCE_EDGETABLE_JUCEHEADER__ | ||||
| @@ -10543,14 +10544,14 @@ public: | |||||
| void createStrokedPath (Path& destPath, | void createStrokedPath (Path& destPath, | ||||
| const Path& sourcePath, | const Path& sourcePath, | ||||
| const AffineTransform& transform = AffineTransform::identity, | const AffineTransform& transform = AffineTransform::identity, | ||||
| const float extraAccuracy = 1.0f) const throw(); | |||||
| const float extraAccuracy = 1.0f) const; | |||||
| void createDashedStroke (Path& destPath, | void createDashedStroke (Path& destPath, | ||||
| const Path& sourcePath, | const Path& sourcePath, | ||||
| const float* dashLengths, | const float* dashLengths, | ||||
| int numDashLengths, | int numDashLengths, | ||||
| const AffineTransform& transform = AffineTransform::identity, | const AffineTransform& transform = AffineTransform::identity, | ||||
| const float extraAccuracy = 1.0f) const throw(); | |||||
| const float extraAccuracy = 1.0f) const; | |||||
| float getStrokeThickness() const throw() { return thickness; } | float getStrokeThickness() const throw() { return thickness; } | ||||
| @@ -110,19 +110,16 @@ bool AudioFormatReader::read (int** destSamples, | |||||
| return true; | return true; | ||||
| } | } | ||||
| static void findMaxMin (const float* src, const int num, | |||||
| float& maxVal, float& minVal) | |||||
| static void findAudioBufferMaxMin (const float* const buffer, const int num, float& maxVal, float& minVal) throw() | |||||
| { | { | ||||
| float mn = src[0]; | |||||
| float mn = buffer[0]; | |||||
| float mx = mn; | float mx = mn; | ||||
| for (int i = 1; i < num; ++i) | for (int i = 1; i < num; ++i) | ||||
| { | { | ||||
| const float s = src[i]; | |||||
| if (s > mx) | |||||
| mx = s; | |||||
| if (s < mn) | |||||
| mn = s; | |||||
| const float s = buffer[i]; | |||||
| if (s > mx) mx = s; | |||||
| if (s < mn) mn = s; | |||||
| } | } | ||||
| maxVal = mx; | maxVal = mx; | ||||
| @@ -167,13 +164,13 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, | |||||
| startSampleInFile += numToDo; | startSampleInFile += numToDo; | ||||
| float bufmin, bufmax; | float bufmin, bufmax; | ||||
| findMaxMin ((float*) tempBuffer[0], numToDo, bufmax, bufmin); | |||||
| findAudioBufferMaxMin ((float*) tempBuffer[0], numToDo, bufmax, bufmin); | |||||
| lmin = jmin (lmin, bufmin); | lmin = jmin (lmin, bufmin); | ||||
| lmax = jmax (lmax, bufmax); | lmax = jmax (lmax, bufmax); | ||||
| if (numChannels > 1) | if (numChannels > 1) | ||||
| { | { | ||||
| findMaxMin ((float*) tempBuffer[1], numToDo, bufmax, bufmin); | |||||
| findAudioBufferMaxMin ((float*) tempBuffer[1], numToDo, bufmax, bufmin); | |||||
| rmin = jmin (rmin, bufmin); | rmin = jmin (rmin, bufmin); | ||||
| rmax = jmax (rmax, bufmax); | rmax = jmax (rmax, bufmax); | ||||
| } | } | ||||
| @@ -45,26 +45,25 @@ struct AudioThumbnailDataFormat | |||||
| int sampleRate; | int sampleRate; | ||||
| char future[16]; | char future[16]; | ||||
| char data[1]; | char data[1]; | ||||
| }; | |||||
| #if JUCE_BIG_ENDIAN | |||||
| static void swap (int& n) { n = (int) ByteOrder::swap ((uint32) n); } | |||||
| static void swap (int64& n) { n = (int64) ByteOrder::swap ((uint64) n); } | |||||
| #endif | |||||
| void swapEndiannessIfNeeded() throw() | |||||
| { | |||||
| #if JUCE_BIG_ENDIAN | |||||
| flip (samplesPerThumbSample); | |||||
| flip (totalSamples); | |||||
| flip (numFinishedSamples); | |||||
| flip (numThumbnailSamples); | |||||
| flip (numChannels); | |||||
| flip (sampleRate); | |||||
| #endif | |||||
| } | |||||
| static void swapEndiannessIfNeeded (AudioThumbnailDataFormat* const d) | |||||
| { | |||||
| (void) d; | |||||
| #if JUCE_BIG_ENDIAN | |||||
| swap (d->samplesPerThumbSample); | |||||
| swap (d->totalSamples); | |||||
| swap (d->numFinishedSamples); | |||||
| swap (d->numThumbnailSamples); | |||||
| swap (d->numChannels); | |||||
| swap (d->sampleRate); | |||||
| #endif | |||||
| } | |||||
| private: | |||||
| #if JUCE_BIG_ENDIAN | |||||
| static void flip (int& n) { n = (int) ByteOrder::swap ((uint32) n); } | |||||
| static void flip (int64& n) { n = (int64) ByteOrder::swap ((uint64) n); } | |||||
| #endif | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| AudioThumbnail::AudioThumbnail (const int orginalSamplesPerThumbnailSample_, | AudioThumbnail::AudioThumbnail (const int orginalSamplesPerThumbnailSample_, | ||||
| @@ -197,7 +196,7 @@ void AudioThumbnail::loadFrom (InputStream& input) | |||||
| input.readIntoMemoryBlock (data); | input.readIntoMemoryBlock (data); | ||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | ||||
| swapEndiannessIfNeeded (d); | |||||
| d->swapEndiannessIfNeeded(); | |||||
| if (! (d->thumbnailMagic[0] == 'j' | if (! (d->thumbnailMagic[0] == 'j' | ||||
| && d->thumbnailMagic[1] == 'a' | && d->thumbnailMagic[1] == 'a' | ||||
| @@ -214,9 +213,9 @@ void AudioThumbnail::loadFrom (InputStream& input) | |||||
| void AudioThumbnail::saveTo (OutputStream& output) const | void AudioThumbnail::saveTo (OutputStream& output) const | ||||
| { | { | ||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | ||||
| swapEndiannessIfNeeded (d); | |||||
| d->swapEndiannessIfNeeded(); | |||||
| output.write (data.getData(), (int) data.getSize()); | output.write (data.getData(), (int) data.getSize()); | ||||
| swapEndiannessIfNeeded (d); | |||||
| d->swapEndiannessIfNeeded(); | |||||
| } | } | ||||
| bool AudioThumbnail::initialiseFromAudioFile (AudioFormatReader& fileReader) | bool AudioThumbnail::initialiseFromAudioFile (AudioFormatReader& fileReader) | ||||
| @@ -32,17 +32,137 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| struct TempoInfo | |||||
| namespace MidiFileHelpers | |||||
| { | { | ||||
| double bpm, timestamp; | |||||
| }; | |||||
| static void writeVariableLengthInt (OutputStream& out, unsigned int v) | |||||
| { | |||||
| unsigned int buffer = v & 0x7F; | |||||
| struct TimeSigInfo | |||||
| { | |||||
| int numerator, denominator; | |||||
| double timestamp; | |||||
| }; | |||||
| while ((v >>= 7) != 0) | |||||
| { | |||||
| buffer <<= 8; | |||||
| buffer |= ((v & 0x7F) | 0x80); | |||||
| } | |||||
| for (;;) | |||||
| { | |||||
| out.writeByte ((char) buffer); | |||||
| if (buffer & 0x80) | |||||
| buffer >>= 8; | |||||
| else | |||||
| break; | |||||
| } | |||||
| } | |||||
| static bool parseMidiHeader (const char* &data, short& timeFormat, short& fileType, short& numberOfTracks) throw() | |||||
| { | |||||
| unsigned int ch = (int) ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| if (ch != ByteOrder::bigEndianInt ("MThd")) | |||||
| { | |||||
| bool ok = false; | |||||
| if (ch == ByteOrder::bigEndianInt ("RIFF")) | |||||
| { | |||||
| for (int i = 0; i < 8; ++i) | |||||
| { | |||||
| ch = ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| if (ch == ByteOrder::bigEndianInt ("MThd")) | |||||
| { | |||||
| ok = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (! ok) | |||||
| return false; | |||||
| } | |||||
| unsigned int bytesRemaining = ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| fileType = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| numberOfTracks = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| timeFormat = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| bytesRemaining -= 6; | |||||
| data += bytesRemaining; | |||||
| return true; | |||||
| } | |||||
| static double convertTicksToSeconds (const double time, | |||||
| const MidiMessageSequence& tempoEvents, | |||||
| const int timeFormat) | |||||
| { | |||||
| if (timeFormat > 0) | |||||
| { | |||||
| int numer = 4, denom = 4; | |||||
| double tempoTime = 0.0, correctedTempoTime = 0.0; | |||||
| const double tickLen = 1.0 / (timeFormat & 0x7fff); | |||||
| double secsPerTick = 0.5 * tickLen; | |||||
| const int numEvents = tempoEvents.getNumEvents(); | |||||
| for (int i = 0; i < numEvents; ++i) | |||||
| { | |||||
| const MidiMessage& m = tempoEvents.getEventPointer(i)->message; | |||||
| if (time <= m.getTimeStamp()) | |||||
| break; | |||||
| if (timeFormat > 0) | |||||
| { | |||||
| correctedTempoTime = correctedTempoTime | |||||
| + (m.getTimeStamp() - tempoTime) * secsPerTick; | |||||
| } | |||||
| else | |||||
| { | |||||
| correctedTempoTime = tickLen * m.getTimeStamp() / (((timeFormat & 0x7fff) >> 8) * (timeFormat & 0xff)); | |||||
| } | |||||
| tempoTime = m.getTimeStamp(); | |||||
| if (m.isTempoMetaEvent()) | |||||
| secsPerTick = tickLen * m.getTempoSecondsPerQuarterNote(); | |||||
| else if (m.isTimeSignatureMetaEvent()) | |||||
| m.getTimeSignatureInfo (numer, denom); | |||||
| while (i + 1 < numEvents) | |||||
| { | |||||
| const MidiMessage& m2 = tempoEvents.getEventPointer(i + 1)->message; | |||||
| if (m2.getTimeStamp() == tempoTime) | |||||
| { | |||||
| ++i; | |||||
| if (m2.isTempoMetaEvent()) | |||||
| secsPerTick = tickLen * m2.getTempoSecondsPerQuarterNote(); | |||||
| else if (m2.isTimeSignatureMetaEvent()) | |||||
| m2.getTimeSignatureInfo (numer, denom); | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return correctedTempoTime + (time - tempoTime) * secsPerTick; | |||||
| } | |||||
| else | |||||
| { | |||||
| return time / (((timeFormat & 0x7fff) >> 8) * (timeFormat & 0xff)); | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | |||||
| MidiFile::MidiFile() throw() | MidiFile::MidiFile() throw() | ||||
| : timeFormat ((short) (unsigned short) 0xe728) | : timeFormat ((short) (unsigned short) 0xe728) | ||||
| { | { | ||||
| @@ -135,51 +255,6 @@ double MidiFile::getLastTimestamp() const | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static bool parseMidiHeader (const char* &data, | |||||
| short& timeFormat, | |||||
| short& fileType, | |||||
| short& numberOfTracks) | |||||
| { | |||||
| unsigned int ch = (int) ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| if (ch != ByteOrder::bigEndianInt ("MThd")) | |||||
| { | |||||
| bool ok = false; | |||||
| if (ch == ByteOrder::bigEndianInt ("RIFF")) | |||||
| { | |||||
| for (int i = 0; i < 8; ++i) | |||||
| { | |||||
| ch = ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| if (ch == ByteOrder::bigEndianInt ("MThd")) | |||||
| { | |||||
| ok = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (! ok) | |||||
| return false; | |||||
| } | |||||
| unsigned int bytesRemaining = ByteOrder::bigEndianInt (data); | |||||
| data += 4; | |||||
| fileType = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| numberOfTracks = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| timeFormat = (short) ByteOrder::bigEndianShort (data); | |||||
| data += 2; | |||||
| bytesRemaining -= 6; | |||||
| data += bytesRemaining; | |||||
| return true; | |||||
| } | |||||
| bool MidiFile::readFrom (InputStream& sourceStream) | bool MidiFile::readFrom (InputStream& sourceStream) | ||||
| { | { | ||||
| clear(); | clear(); | ||||
| @@ -194,7 +269,7 @@ bool MidiFile::readFrom (InputStream& sourceStream) | |||||
| const char* d = (char*) data.getData(); | const char* d = (char*) data.getData(); | ||||
| short fileType, expectedTracks; | short fileType, expectedTracks; | ||||
| if (size > 16 && parseMidiHeader (d, timeFormat, fileType, expectedTracks)) | |||||
| if (size > 16 && MidiFileHelpers::parseMidiHeader (d, timeFormat, fileType, expectedTracks)) | |||||
| { | { | ||||
| size -= (int) (d - (char*) data.getData()); | size -= (int) (d - (char*) data.getData()); | ||||
| @@ -291,70 +366,6 @@ void MidiFile::readNextTrack (const char* data, int size) | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static double convertTicksToSeconds (const double time, | |||||
| const MidiMessageSequence& tempoEvents, | |||||
| const int timeFormat) | |||||
| { | |||||
| if (timeFormat > 0) | |||||
| { | |||||
| int numer = 4, denom = 4; | |||||
| double tempoTime = 0.0, correctedTempoTime = 0.0; | |||||
| const double tickLen = 1.0 / (timeFormat & 0x7fff); | |||||
| double secsPerTick = 0.5 * tickLen; | |||||
| const int numEvents = tempoEvents.getNumEvents(); | |||||
| for (int i = 0; i < numEvents; ++i) | |||||
| { | |||||
| const MidiMessage& m = tempoEvents.getEventPointer(i)->message; | |||||
| if (time <= m.getTimeStamp()) | |||||
| break; | |||||
| if (timeFormat > 0) | |||||
| { | |||||
| correctedTempoTime = correctedTempoTime | |||||
| + (m.getTimeStamp() - tempoTime) * secsPerTick; | |||||
| } | |||||
| else | |||||
| { | |||||
| correctedTempoTime = tickLen * m.getTimeStamp() / (((timeFormat & 0x7fff) >> 8) * (timeFormat & 0xff)); | |||||
| } | |||||
| tempoTime = m.getTimeStamp(); | |||||
| if (m.isTempoMetaEvent()) | |||||
| secsPerTick = tickLen * m.getTempoSecondsPerQuarterNote(); | |||||
| else if (m.isTimeSignatureMetaEvent()) | |||||
| m.getTimeSignatureInfo (numer, denom); | |||||
| while (i + 1 < numEvents) | |||||
| { | |||||
| const MidiMessage& m2 = tempoEvents.getEventPointer(i + 1)->message; | |||||
| if (m2.getTimeStamp() == tempoTime) | |||||
| { | |||||
| ++i; | |||||
| if (m2.isTempoMetaEvent()) | |||||
| secsPerTick = tickLen * m2.getTempoSecondsPerQuarterNote(); | |||||
| else if (m2.isTimeSignatureMetaEvent()) | |||||
| m2.getTimeSignatureInfo (numer, denom); | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return correctedTempoTime + (time - tempoTime) * secsPerTick; | |||||
| } | |||||
| else | |||||
| { | |||||
| return time / (((timeFormat & 0x7fff) >> 8) * (timeFormat & 0xff)); | |||||
| } | |||||
| } | |||||
| void MidiFile::convertTimestampTicksToSeconds() | void MidiFile::convertTimestampTicksToSeconds() | ||||
| { | { | ||||
| MidiMessageSequence tempoEvents; | MidiMessageSequence tempoEvents; | ||||
| @@ -369,35 +380,14 @@ void MidiFile::convertTimestampTicksToSeconds() | |||||
| { | { | ||||
| MidiMessage& m = ms.getEventPointer(j)->message; | MidiMessage& m = ms.getEventPointer(j)->message; | ||||
| m.setTimeStamp (convertTicksToSeconds (m.getTimeStamp(), | |||||
| tempoEvents, | |||||
| timeFormat)); | |||||
| m.setTimeStamp (MidiFileHelpers::convertTicksToSeconds (m.getTimeStamp(), | |||||
| tempoEvents, | |||||
| timeFormat)); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static void writeVariableLengthInt (OutputStream& out, unsigned int v) | |||||
| { | |||||
| unsigned int buffer = v & 0x7F; | |||||
| while ((v >>= 7) != 0) | |||||
| { | |||||
| buffer <<= 8; | |||||
| buffer |= ((v & 0x7F) | 0x80); | |||||
| } | |||||
| for (;;) | |||||
| { | |||||
| out.writeByte ((char) buffer); | |||||
| if (buffer & 0x80) | |||||
| buffer >>= 8; | |||||
| else | |||||
| break; | |||||
| } | |||||
| } | |||||
| bool MidiFile::writeTo (OutputStream& out) | bool MidiFile::writeTo (OutputStream& out) | ||||
| { | { | ||||
| out.writeIntBigEndian ((int) ByteOrder::bigEndianInt ("MThd")); | out.writeIntBigEndian ((int) ByteOrder::bigEndianInt ("MThd")); | ||||
| @@ -414,8 +404,6 @@ bool MidiFile::writeTo (OutputStream& out) | |||||
| return true; | return true; | ||||
| } | } | ||||
| //============================================================================== | |||||
| void MidiFile::writeTrack (OutputStream& mainOut, | void MidiFile::writeTrack (OutputStream& mainOut, | ||||
| const int trackNum) | const int trackNum) | ||||
| { | { | ||||
| @@ -432,7 +420,7 @@ void MidiFile::writeTrack (OutputStream& mainOut, | |||||
| const int tick = roundToInt (mm.getTimeStamp()); | const int tick = roundToInt (mm.getTimeStamp()); | ||||
| const int delta = jmax (0, tick - lastTick); | const int delta = jmax (0, tick - lastTick); | ||||
| writeVariableLengthInt (out, delta); | |||||
| MidiFileHelpers::writeVariableLengthInt (out, delta); | |||||
| lastTick = tick; | lastTick = tick; | ||||
| const char statusByte = *(mm.getRawData()); | const char statusByte = *(mm.getRawData()); | ||||
| @@ -36,7 +36,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| MD5::MD5() | MD5::MD5() | ||||
| { | { | ||||
| zeromem (result, sizeof (result)); | |||||
| zerostruct (result); | |||||
| } | } | ||||
| MD5::MD5 (const MD5& other) | MD5::MD5 (const MD5& other) | ||||
| @@ -121,13 +121,62 @@ MD5::MD5 (const File& file) | |||||
| if (fin != 0) | if (fin != 0) | ||||
| processStream (*fin, -1); | processStream (*fin, -1); | ||||
| else | else | ||||
| zeromem (result, sizeof (result)); | |||||
| zerostruct (result); | |||||
| } | } | ||||
| MD5::~MD5() | MD5::~MD5() | ||||
| { | { | ||||
| } | } | ||||
| //============================================================================== | |||||
| namespace MD5Functions | |||||
| { | |||||
| static void encode (uint8* const output, const uint32* const input, const int numBytes) throw() | |||||
| { | |||||
| uint32* const o = (uint32*) output; | |||||
| for (int i = 0; i < (numBytes >> 2); ++i) | |||||
| o[i] = ByteOrder::swapIfBigEndian (input [i]); | |||||
| } | |||||
| static void decode (uint32* const output, const uint8* const input, const int numBytes) throw() | |||||
| { | |||||
| for (int i = 0; i < (numBytes >> 2); ++i) | |||||
| output[i] = ByteOrder::littleEndianInt ((const char*) input + (i << 2)); | |||||
| } | |||||
| static inline uint32 F (const uint32 x, const uint32 y, const uint32 z) throw() { return (x & y) | (~x & z); } | |||||
| static inline uint32 G (const uint32 x, const uint32 y, const uint32 z) throw() { return (x & z) | (y & ~z); } | |||||
| static inline uint32 H (const uint32 x, const uint32 y, const uint32 z) throw() { return x ^ y ^ z; } | |||||
| static inline uint32 I (const uint32 x, const uint32 y, const uint32 z) throw() { return y ^ (x | ~z); } | |||||
| static inline uint32 rotateLeft (const uint32 x, const uint32 n) throw() { return (x << n) | (x >> (32 - n)); } | |||||
| static void FF (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += F (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void GG (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += G (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void HH (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += H (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void II (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += I (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| MD5::ProcessContext::ProcessContext() | MD5::ProcessContext::ProcessContext() | ||||
| { | { | ||||
| @@ -175,30 +224,11 @@ void MD5::ProcessContext::processBlock (const uint8* const data, size_t dataSize | |||||
| memcpy (buffer + bufferPos, data + i, dataSize - i); | memcpy (buffer + bufferPos, data + i, dataSize - i); | ||||
| } | } | ||||
| //============================================================================== | |||||
| static void encode (uint8* const output, | |||||
| const uint32* const input, | |||||
| const int numBytes) | |||||
| { | |||||
| uint32* const o = (uint32*) output; | |||||
| for (int i = 0; i < (numBytes >> 2); ++i) | |||||
| o[i] = ByteOrder::swapIfBigEndian (input [i]); | |||||
| } | |||||
| static void decode (uint32* const output, | |||||
| const uint8* const input, | |||||
| const int numBytes) | |||||
| { | |||||
| for (int i = 0; i < (numBytes >> 2); ++i) | |||||
| output[i] = ByteOrder::littleEndianInt ((const char*) input + (i << 2)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void MD5::ProcessContext::finish (uint8* const result) | void MD5::ProcessContext::finish (uint8* const result) | ||||
| { | { | ||||
| unsigned char encodedLength[8]; | unsigned char encodedLength[8]; | ||||
| encode (encodedLength, count, 8); | |||||
| MD5Functions::encode (encodedLength, count, 8); | |||||
| // Pad out to 56 mod 64. | // Pad out to 56 mod 64. | ||||
| const int index = (uint32) ((count[0] >> 3) & 0x3f); | const int index = (uint32) ((count[0] >> 3) & 0x3f); | ||||
| @@ -213,48 +243,14 @@ void MD5::ProcessContext::finish (uint8* const result) | |||||
| processBlock (encodedLength, 8); | processBlock (encodedLength, 8); | ||||
| encode (result, state, 16); | |||||
| zeromem (buffer, sizeof (buffer)); | |||||
| } | |||||
| //============================================================================== | |||||
| namespace MD5Functions | |||||
| { | |||||
| static inline uint32 F (const uint32 x, const uint32 y, const uint32 z) throw() { return (x & y) | (~x & z); } | |||||
| static inline uint32 G (const uint32 x, const uint32 y, const uint32 z) throw() { return (x & z) | (y & ~z); } | |||||
| static inline uint32 H (const uint32 x, const uint32 y, const uint32 z) throw() { return x ^ y ^ z; } | |||||
| static inline uint32 I (const uint32 x, const uint32 y, const uint32 z) throw() { return y ^ (x | ~z); } | |||||
| static inline uint32 rotateLeft (const uint32 x, const uint32 n) throw() { return (x << n) | (x >> (32 - n)); } | |||||
| static void FF (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += F (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void GG (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += G (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void HH (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += H (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| static void II (uint32& a, const uint32 b, const uint32 c, const uint32 d, const uint32 x, const uint32 s, const uint32 ac) throw() | |||||
| { | |||||
| a += I (b, c, d) + x + ac; | |||||
| a = rotateLeft (a, s) + b; | |||||
| } | |||||
| MD5Functions::encode (result, state, sizeof (result)); | |||||
| zerostruct (buffer); | |||||
| } | } | ||||
| void MD5::ProcessContext::transform (const uint8* const bufferToTransform) | void MD5::ProcessContext::transform (const uint8* const bufferToTransform) | ||||
| { | { | ||||
| using namespace MD5Functions; | |||||
| uint32 a = state[0]; | uint32 a = state[0]; | ||||
| uint32 b = state[1]; | uint32 b = state[1]; | ||||
| uint32 c = state[2]; | uint32 c = state[2]; | ||||
| @@ -269,7 +265,6 @@ void MD5::ProcessContext::transform (const uint8* const bufferToTransform) | |||||
| S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21 | S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21 | ||||
| }; | }; | ||||
| using namespace MD5Functions; | |||||
| FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ | ||||
| FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ | ||||
| FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ | ||||
| @@ -349,18 +344,18 @@ void MD5::ProcessContext::transform (const uint8* const bufferToTransform) | |||||
| //============================================================================== | //============================================================================== | ||||
| const MemoryBlock MD5::getRawChecksumData() const | const MemoryBlock MD5::getRawChecksumData() const | ||||
| { | { | ||||
| return MemoryBlock (result, 16); | |||||
| return MemoryBlock (result, sizeof (result)); | |||||
| } | } | ||||
| const String MD5::toHexString() const | const String MD5::toHexString() const | ||||
| { | { | ||||
| return String::toHexString (result, 16, 0); | |||||
| return String::toHexString (result, sizeof (result), 0); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| bool MD5::operator== (const MD5& other) const | bool MD5::operator== (const MD5& other) const | ||||
| { | { | ||||
| return memcmp (result, other.result, 16) == 0; | |||||
| return memcmp (result, other.result, sizeof (result)) == 0; | |||||
| } | } | ||||
| bool MD5::operator!= (const MD5& other) const | bool MD5::operator!= (const MD5& other) const | ||||
| @@ -33,85 +33,88 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| static void createSmallSieve (const int numBits, BitArray& result) throw() | |||||
| namespace PrimesHelpers | |||||
| { | { | ||||
| result.setBit (numBits); | |||||
| result.clearBit (numBits); // to enlarge the array | |||||
| static void createSmallSieve (const int numBits, BitArray& result) throw() | |||||
| { | |||||
| result.setBit (numBits); | |||||
| result.clearBit (numBits); // to enlarge the array | |||||
| result.setBit (0); | |||||
| int n = 2; | |||||
| result.setBit (0); | |||||
| int n = 2; | |||||
| do | |||||
| { | |||||
| for (int i = n + n; i < numBits; i += n) | |||||
| result.setBit (i); | |||||
| do | |||||
| { | |||||
| for (int i = n + n; i < numBits; i += n) | |||||
| result.setBit (i); | |||||
| n = result.findNextClearBit (n + 1); | |||||
| n = result.findNextClearBit (n + 1); | |||||
| } | |||||
| while (n <= (numBits >> 1)); | |||||
| } | } | ||||
| while (n <= (numBits >> 1)); | |||||
| } | |||||
| static void bigSieve (const BitArray& base, | |||||
| const int numBits, | |||||
| BitArray& result, | |||||
| const BitArray& smallSieve, | |||||
| const int smallSieveSize) throw() | |||||
| { | |||||
| jassert (! base[0]); // must be even! | |||||
| static void bigSieve (const BitArray& base, | |||||
| const int numBits, | |||||
| BitArray& result, | |||||
| const BitArray& smallSieve, | |||||
| const int smallSieveSize) throw() | |||||
| { | |||||
| jassert (! base[0]); // must be even! | |||||
| result.setBit (numBits); | |||||
| result.clearBit (numBits); // to enlarge the array | |||||
| result.setBit (numBits); | |||||
| result.clearBit (numBits); // to enlarge the array | |||||
| int index = smallSieve.findNextClearBit (0); | |||||
| int index = smallSieve.findNextClearBit (0); | |||||
| do | |||||
| { | |||||
| const int prime = (index << 1) + 1; | |||||
| do | |||||
| { | |||||
| const int prime = (index << 1) + 1; | |||||
| BitArray r (base); | |||||
| BitArray remainder; | |||||
| r.divideBy (prime, remainder); | |||||
| BitArray r (base); | |||||
| BitArray remainder; | |||||
| r.divideBy (prime, remainder); | |||||
| int i = prime - remainder.getBitRangeAsInt (0, 32); | |||||
| int i = prime - remainder.getBitRangeAsInt (0, 32); | |||||
| if (r.isEmpty()) | |||||
| i += prime; | |||||
| if (r.isEmpty()) | |||||
| i += prime; | |||||
| if ((i & 1) == 0) | |||||
| i += prime; | |||||
| if ((i & 1) == 0) | |||||
| i += prime; | |||||
| i = (i - 1) >> 1; | |||||
| i = (i - 1) >> 1; | |||||
| while (i < numBits) | |||||
| { | |||||
| result.setBit (i); | |||||
| i += prime; | |||||
| } | |||||
| while (i < numBits) | |||||
| { | |||||
| result.setBit (i); | |||||
| i += prime; | |||||
| } | |||||
| index = smallSieve.findNextClearBit (index + 1); | |||||
| index = smallSieve.findNextClearBit (index + 1); | |||||
| } | |||||
| while (index < smallSieveSize); | |||||
| } | } | ||||
| while (index < smallSieveSize); | |||||
| } | |||||
| static bool findCandidate (const BitArray& base, | |||||
| const BitArray& sieve, | |||||
| const int numBits, | |||||
| BitArray& result, | |||||
| const int certainty) throw() | |||||
| { | |||||
| for (int i = 0; i < numBits; ++i) | |||||
| static bool findCandidate (const BitArray& base, | |||||
| const BitArray& sieve, | |||||
| const int numBits, | |||||
| BitArray& result, | |||||
| const int certainty) throw() | |||||
| { | { | ||||
| if (! sieve[i]) | |||||
| for (int i = 0; i < numBits; ++i) | |||||
| { | { | ||||
| result = base; | |||||
| result.add (BitArray ((unsigned int) ((i << 1) + 1))); | |||||
| if (! sieve[i]) | |||||
| { | |||||
| result = base; | |||||
| result.add (BitArray ((unsigned int) ((i << 1) + 1))); | |||||
| if (Primes::isProbablyPrime (result, certainty)) | |||||
| return true; | |||||
| if (Primes::isProbablyPrime (result, certainty)) | |||||
| return true; | |||||
| } | |||||
| } | } | ||||
| } | |||||
| return false; | |||||
| return false; | |||||
| } | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -120,6 +123,7 @@ const BitArray Primes::createProbablePrime (const int bitLength, | |||||
| const int* randomSeeds, | const int* randomSeeds, | ||||
| int numRandomSeeds) throw() | int numRandomSeeds) throw() | ||||
| { | { | ||||
| using namespace PrimesHelpers; | |||||
| int defaultSeeds [16]; | int defaultSeeds [16]; | ||||
| if (numRandomSeeds <= 0) | if (numRandomSeeds <= 0) | ||||
| @@ -178,6 +182,8 @@ const BitArray Primes::createProbablePrime (const int bitLength, | |||||
| static bool passesMillerRabin (const BitArray& n, int iterations) throw() | static bool passesMillerRabin (const BitArray& n, int iterations) throw() | ||||
| { | { | ||||
| using namespace PrimesHelpers; | |||||
| const BitArray one (1); | const BitArray one (1); | ||||
| const BitArray two (2); | const BitArray two (2); | ||||
| @@ -41,58 +41,61 @@ KeyboardFocusTraverser::~KeyboardFocusTraverser() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| // This will sort a set of components, so that they are ordered in terms of | |||||
| // left-to-right and then top-to-bottom. | |||||
| class ScreenPositionComparator | |||||
| namespace KeyboardFocusHelpers | |||||
| { | { | ||||
| public: | |||||
| ScreenPositionComparator() {} | |||||
| static int compareElements (const Component* const first, const Component* const second) throw() | |||||
| // This will sort a set of components, so that they are ordered in terms of | |||||
| // left-to-right and then top-to-bottom. | |||||
| class ScreenPositionComparator | |||||
| { | { | ||||
| int explicitOrder1 = first->getExplicitFocusOrder(); | |||||
| if (explicitOrder1 <= 0) | |||||
| explicitOrder1 = std::numeric_limits<int>::max() / 2; | |||||
| public: | |||||
| ScreenPositionComparator() {} | |||||
| int explicitOrder2 = second->getExplicitFocusOrder(); | |||||
| if (explicitOrder2 <= 0) | |||||
| explicitOrder2 = std::numeric_limits<int>::max() / 2; | |||||
| static int compareElements (const Component* const first, const Component* const second) throw() | |||||
| { | |||||
| int explicitOrder1 = first->getExplicitFocusOrder(); | |||||
| if (explicitOrder1 <= 0) | |||||
| explicitOrder1 = std::numeric_limits<int>::max() / 2; | |||||
| if (explicitOrder1 != explicitOrder2) | |||||
| return explicitOrder1 - explicitOrder2; | |||||
| int explicitOrder2 = second->getExplicitFocusOrder(); | |||||
| if (explicitOrder2 <= 0) | |||||
| explicitOrder2 = std::numeric_limits<int>::max() / 2; | |||||
| const int diff = first->getY() - second->getY(); | |||||
| if (explicitOrder1 != explicitOrder2) | |||||
| return explicitOrder1 - explicitOrder2; | |||||
| return (diff == 0) ? first->getX() - second->getX() | |||||
| : diff; | |||||
| } | |||||
| }; | |||||
| const int diff = first->getY() - second->getY(); | |||||
| static void findAllFocusableComponents (Component* const parent, Array <Component*>& comps) | |||||
| { | |||||
| if (parent->getNumChildComponents() > 0) | |||||
| { | |||||
| Array <Component*> localComps; | |||||
| ScreenPositionComparator comparator; | |||||
| return (diff == 0) ? first->getX() - second->getX() | |||||
| : diff; | |||||
| } | |||||
| }; | |||||
| int i; | |||||
| for (i = parent->getNumChildComponents(); --i >= 0;) | |||||
| static void findAllFocusableComponents (Component* const parent, Array <Component*>& comps) | |||||
| { | |||||
| if (parent->getNumChildComponents() > 0) | |||||
| { | { | ||||
| Component* const c = parent->getChildComponent (i); | |||||
| Array <Component*> localComps; | |||||
| ScreenPositionComparator comparator; | |||||
| if (c->isVisible() && c->isEnabled()) | |||||
| localComps.addSorted (comparator, c); | |||||
| } | |||||
| int i; | |||||
| for (i = parent->getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = parent->getChildComponent (i); | |||||
| for (i = 0; i < localComps.size(); ++i) | |||||
| { | |||||
| Component* const c = localComps.getUnchecked (i); | |||||
| if (c->isVisible() && c->isEnabled()) | |||||
| localComps.addSorted (comparator, c); | |||||
| } | |||||
| if (c->getWantsKeyboardFocus()) | |||||
| comps.add (c); | |||||
| for (i = 0; i < localComps.size(); ++i) | |||||
| { | |||||
| Component* const c = localComps.getUnchecked (i); | |||||
| if (c->getWantsKeyboardFocus()) | |||||
| comps.add (c); | |||||
| if (! c->isFocusContainer()) | |||||
| findAllFocusableComponents (c, comps); | |||||
| if (! c->isFocusContainer()) | |||||
| findAllFocusableComponents (c, comps); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -109,7 +112,7 @@ static Component* getIncrementedComponent (Component* const current, const int d | |||||
| if (focusContainer != 0) | if (focusContainer != 0) | ||||
| { | { | ||||
| Array <Component*> comps; | Array <Component*> comps; | ||||
| findAllFocusableComponents (focusContainer, comps); | |||||
| KeyboardFocusHelpers::findAllFocusableComponents (focusContainer, comps); | |||||
| if (comps.size() > 0) | if (comps.size() > 0) | ||||
| { | { | ||||
| @@ -137,7 +140,7 @@ Component* KeyboardFocusTraverser::getDefaultComponent (Component* parentCompone | |||||
| Array <Component*> comps; | Array <Component*> comps; | ||||
| if (parentComponent != 0) | if (parentComponent != 0) | ||||
| findAllFocusableComponents (parentComponent, comps); | |||||
| KeyboardFocusHelpers::findAllFocusableComponents (parentComponent, comps); | |||||
| return comps.getFirst(); | return comps.getFirst(); | ||||
| } | } | ||||
| @@ -34,17 +34,6 @@ BEGIN_JUCE_NAMESPACE | |||||
| const int juce_edgeTableDefaultEdgesPerLine = 32; | const int juce_edgeTableDefaultEdgesPerLine = 32; | ||||
| //============================================================================== | |||||
| static void copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) throw() | |||||
| { | |||||
| while (--numLines >= 0) | |||||
| { | |||||
| memcpy (dest, src, (src[0] * 2 + 1) * sizeof (int)); | |||||
| src += srcLineStride; | |||||
| dest += destLineStride; | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| EdgeTable::EdgeTable (const Rectangle<int>& bounds_, | EdgeTable::EdgeTable (const Rectangle<int>& bounds_, | ||||
| const Path& path, const AffineTransform& transform) throw() | const Path& path, const AffineTransform& transform) throw() | ||||
| @@ -277,6 +266,16 @@ EdgeTable::~EdgeTable() throw() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void EdgeTable::copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) throw() | |||||
| { | |||||
| while (--numLines >= 0) | |||||
| { | |||||
| memcpy (dest, src, (src[0] * 2 + 1) * sizeof (int)); | |||||
| src += srcLineStride; | |||||
| dest += destLineStride; | |||||
| } | |||||
| } | |||||
| void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) throw() | void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) throw() | ||||
| { | { | ||||
| // Convert the table from relative windings to absolute levels.. | // Convert the table from relative windings to absolute levels.. | ||||
| @@ -205,6 +205,7 @@ private: | |||||
| void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); | void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); | ||||
| void clipEdgeTableLineToRange (int* line, int x1, int x2) throw(); | void clipEdgeTableLineToRange (int* line, int x1, int x2) throw(); | ||||
| void sanitiseLevels (const bool useNonZeroWinding) throw(); | void sanitiseLevels (const bool useNonZeroWinding) throw(); | ||||
| static void copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) throw(); | |||||
| }; | }; | ||||
| @@ -191,283 +191,286 @@ static bool lineIntersection (const float x1, const float y1, | |||||
| return true; | return true; | ||||
| } | } | ||||
| // part of stroke drawing stuff | |||||
| static void addEdgeAndJoint (Path& destPath, | |||||
| const PathStrokeType::JointStyle style, | |||||
| const float maxMiterExtensionSquared, const float width, | |||||
| const float x1, const float y1, | |||||
| const float x2, const float y2, | |||||
| const float x3, const float y3, | |||||
| const float x4, const float y4, | |||||
| const float midX, const float midY) throw() | |||||
| namespace PathFunctions | |||||
| { | { | ||||
| if (style == PathStrokeType::beveled | |||||
| || (x3 == x4 && y3 == y4) | |||||
| || (x1 == x2 && y1 == y2)) | |||||
| // part of stroke drawing stuff | |||||
| static void addEdgeAndJoint (Path& destPath, | |||||
| const PathStrokeType::JointStyle style, | |||||
| const float maxMiterExtensionSquared, const float width, | |||||
| const float x1, const float y1, | |||||
| const float x2, const float y2, | |||||
| const float x3, const float y3, | |||||
| const float x4, const float y4, | |||||
| const float midX, const float midY) | |||||
| { | { | ||||
| destPath.lineTo (x2, y2); | |||||
| destPath.lineTo (x3, y3); | |||||
| } | |||||
| else | |||||
| { | |||||
| float jx, jy, distanceBeyondLine1EndSquared; | |||||
| // if they intersect, use this point.. | |||||
| if (lineIntersection (x1, y1, x2, y2, | |||||
| x3, y3, x4, y4, | |||||
| jx, jy, distanceBeyondLine1EndSquared)) | |||||
| if (style == PathStrokeType::beveled | |||||
| || (x3 == x4 && y3 == y4) | |||||
| || (x1 == x2 && y1 == y2)) | |||||
| { | { | ||||
| destPath.lineTo (jx, jy); | |||||
| destPath.lineTo (x2, y2); | |||||
| destPath.lineTo (x3, y3); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (style == PathStrokeType::mitered) | |||||
| float jx, jy, distanceBeyondLine1EndSquared; | |||||
| // if they intersect, use this point.. | |||||
| if (lineIntersection (x1, y1, x2, y2, | |||||
| x3, y3, x4, y4, | |||||
| jx, jy, distanceBeyondLine1EndSquared)) | |||||
| { | { | ||||
| if (distanceBeyondLine1EndSquared < maxMiterExtensionSquared | |||||
| && distanceBeyondLine1EndSquared > 0.0f) | |||||
| { | |||||
| destPath.lineTo (jx, jy); | |||||
| } | |||||
| else | |||||
| { | |||||
| // the end sticks out too far, so just use a blunt joint | |||||
| destPath.lineTo (x2, y2); | |||||
| destPath.lineTo (x3, y3); | |||||
| } | |||||
| destPath.lineTo (jx, jy); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // curved joints | |||||
| float angle1 = atan2f (x2 - midX, y2 - midY); | |||||
| float angle2 = atan2f (x3 - midX, y3 - midY); | |||||
| const float angleIncrement = 0.1f; | |||||
| destPath.lineTo (x2, y2); | |||||
| if (fabs (angle1 - angle2) > angleIncrement) | |||||
| if (style == PathStrokeType::mitered) | |||||
| { | { | ||||
| if (angle2 > angle1 + float_Pi | |||||
| || (angle2 < angle1 && angle2 >= angle1 - float_Pi)) | |||||
| if (distanceBeyondLine1EndSquared < maxMiterExtensionSquared | |||||
| && distanceBeyondLine1EndSquared > 0.0f) | |||||
| { | |||||
| destPath.lineTo (jx, jy); | |||||
| } | |||||
| else | |||||
| { | { | ||||
| if (angle2 > angle1) | |||||
| angle2 -= float_Pi * 2.0f; | |||||
| // the end sticks out too far, so just use a blunt joint | |||||
| destPath.lineTo (x2, y2); | |||||
| destPath.lineTo (x3, y3); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| // curved joints | |||||
| float angle1 = atan2f (x2 - midX, y2 - midY); | |||||
| float angle2 = atan2f (x3 - midX, y3 - midY); | |||||
| const float angleIncrement = 0.1f; | |||||
| jassert (angle1 <= angle2 + float_Pi); | |||||
| destPath.lineTo (x2, y2); | |||||
| angle1 -= angleIncrement; | |||||
| while (angle1 > angle2) | |||||
| if (fabs (angle1 - angle2) > angleIncrement) | |||||
| { | |||||
| if (angle2 > angle1 + float_Pi | |||||
| || (angle2 < angle1 && angle2 >= angle1 - float_Pi)) | |||||
| { | { | ||||
| destPath.lineTo (midX + width * sinf (angle1), | |||||
| midY + width * cosf (angle1)); | |||||
| if (angle2 > angle1) | |||||
| angle2 -= float_Pi * 2.0f; | |||||
| angle1 -= angleIncrement; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (angle1 > angle2) | |||||
| angle1 -= float_Pi * 2.0f; | |||||
| jassert (angle1 <= angle2 + float_Pi); | |||||
| jassert (angle1 >= angle2 - float_Pi); | |||||
| angle1 -= angleIncrement; | |||||
| while (angle1 > angle2) | |||||
| { | |||||
| destPath.lineTo (midX + width * sinf (angle1), | |||||
| midY + width * cosf (angle1)); | |||||
| angle1 += angleIncrement; | |||||
| while (angle1 < angle2) | |||||
| angle1 -= angleIncrement; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | { | ||||
| destPath.lineTo (midX + width * sinf (angle1), | |||||
| midY + width * cosf (angle1)); | |||||
| if (angle1 > angle2) | |||||
| angle1 -= float_Pi * 2.0f; | |||||
| jassert (angle1 >= angle2 - float_Pi); | |||||
| angle1 += angleIncrement; | angle1 += angleIncrement; | ||||
| while (angle1 < angle2) | |||||
| { | |||||
| destPath.lineTo (midX + width * sinf (angle1), | |||||
| midY + width * cosf (angle1)); | |||||
| angle1 += angleIncrement; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| destPath.lineTo (x3, y3); | |||||
| destPath.lineTo (x3, y3); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| static inline void addLineEnd (Path& destPath, | |||||
| const PathStrokeType::EndCapStyle style, | |||||
| const float x1, const float y1, | |||||
| const float x2, const float y2, | |||||
| const float width) throw() | |||||
| { | |||||
| if (style == PathStrokeType::butt) | |||||
| static void addLineEnd (Path& destPath, | |||||
| const PathStrokeType::EndCapStyle style, | |||||
| const float x1, const float y1, | |||||
| const float x2, const float y2, | |||||
| const float width) | |||||
| { | { | ||||
| destPath.lineTo (x2, y2); | |||||
| } | |||||
| else | |||||
| { | |||||
| float offx1, offy1, offx2, offy2; | |||||
| float dx = x2 - x1; | |||||
| float dy = y2 - y1; | |||||
| const float len = juce_hypotf (dx, dy); | |||||
| if (len == 0) | |||||
| if (style == PathStrokeType::butt) | |||||
| { | { | ||||
| offx1 = offx2 = x1; | |||||
| offy1 = offy2 = y1; | |||||
| } | |||||
| else | |||||
| { | |||||
| const float offset = width / len; | |||||
| dx *= offset; | |||||
| dy *= offset; | |||||
| offx1 = x1 + dy; | |||||
| offy1 = y1 - dx; | |||||
| offx2 = x2 + dy; | |||||
| offy2 = y2 - dx; | |||||
| } | |||||
| if (style == PathStrokeType::square) | |||||
| { | |||||
| // sqaure ends | |||||
| destPath.lineTo (offx1, offy1); | |||||
| destPath.lineTo (offx2, offy2); | |||||
| destPath.lineTo (x2, y2); | destPath.lineTo (x2, y2); | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // rounded ends | |||||
| const float midx = (offx1 + offx2) * 0.5f; | |||||
| const float midy = (offy1 + offy2) * 0.5f; | |||||
| float offx1, offy1, offx2, offy2; | |||||
| destPath.cubicTo (x1 + (offx1 - x1) * 0.55f, y1 + (offy1 - y1) * 0.55f, | |||||
| offx1 + (midx - offx1) * 0.45f, offy1 + (midy - offy1) * 0.45f, | |||||
| midx, midy); | |||||
| float dx = x2 - x1; | |||||
| float dy = y2 - y1; | |||||
| const float len = juce_hypotf (dx, dy); | |||||
| destPath.cubicTo (midx + (offx2 - midx) * 0.55f, midy + (offy2 - midy) * 0.55f, | |||||
| offx2 + (x2 - offx2) * 0.45f, offy2 + (y2 - offy2) * 0.45f, | |||||
| x2, y2); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (len == 0) | |||||
| { | |||||
| offx1 = offx2 = x1; | |||||
| offy1 = offy2 = y1; | |||||
| } | |||||
| else | |||||
| { | |||||
| const float offset = width / len; | |||||
| dx *= offset; | |||||
| dy *= offset; | |||||
| struct LineSection | |||||
| { | |||||
| LineSection() {} | |||||
| LineSection (int) {} | |||||
| float x1, y1, x2, y2; // original line | |||||
| float lx1, ly1, lx2, ly2; // the left-hand stroke | |||||
| float rx1, ry1, rx2, ry2; // the right-hand stroke | |||||
| }; | |||||
| static void addSubPath (Path& destPath, const Array <LineSection>& subPath, | |||||
| const bool isClosed, | |||||
| const float width, const float maxMiterExtensionSquared, | |||||
| const PathStrokeType::JointStyle jointStyle, const PathStrokeType::EndCapStyle endStyle) throw() | |||||
| { | |||||
| jassert (subPath.size() > 0); | |||||
| offx1 = x1 + dy; | |||||
| offy1 = y1 - dx; | |||||
| offx2 = x2 + dy; | |||||
| offy2 = y2 - dx; | |||||
| } | |||||
| const LineSection& firstLine = subPath.getReference (0); | |||||
| if (style == PathStrokeType::square) | |||||
| { | |||||
| // sqaure ends | |||||
| destPath.lineTo (offx1, offy1); | |||||
| destPath.lineTo (offx2, offy2); | |||||
| destPath.lineTo (x2, y2); | |||||
| } | |||||
| else | |||||
| { | |||||
| // rounded ends | |||||
| const float midx = (offx1 + offx2) * 0.5f; | |||||
| const float midy = (offy1 + offy2) * 0.5f; | |||||
| float lastX1 = firstLine.lx1; | |||||
| float lastY1 = firstLine.ly1; | |||||
| float lastX2 = firstLine.lx2; | |||||
| float lastY2 = firstLine.ly2; | |||||
| destPath.cubicTo (x1 + (offx1 - x1) * 0.55f, y1 + (offy1 - y1) * 0.55f, | |||||
| offx1 + (midx - offx1) * 0.45f, offy1 + (midy - offy1) * 0.45f, | |||||
| midx, midy); | |||||
| if (isClosed) | |||||
| { | |||||
| destPath.startNewSubPath (lastX1, lastY1); | |||||
| destPath.cubicTo (midx + (offx2 - midx) * 0.55f, midy + (offy2 - midy) * 0.55f, | |||||
| offx2 + (x2 - offx2) * 0.45f, offy2 + (y2 - offy2) * 0.45f, | |||||
| x2, y2); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| else | |||||
| struct LineSection | |||||
| { | |||||
| LineSection() {} | |||||
| LineSection (int) {} | |||||
| float x1, y1, x2, y2; // original line | |||||
| float lx1, ly1, lx2, ly2; // the left-hand stroke | |||||
| float rx1, ry1, rx2, ry2; // the right-hand stroke | |||||
| }; | |||||
| static void addSubPath (Path& destPath, const Array <LineSection>& subPath, | |||||
| const bool isClosed, | |||||
| const float width, const float maxMiterExtensionSquared, | |||||
| const PathStrokeType::JointStyle jointStyle, const PathStrokeType::EndCapStyle endStyle) | |||||
| { | { | ||||
| destPath.startNewSubPath (firstLine.rx2, firstLine.ry2); | |||||
| jassert (subPath.size() > 0); | |||||
| addLineEnd (destPath, endStyle, | |||||
| firstLine.rx2, firstLine.ry2, | |||||
| lastX1, lastY1, | |||||
| width); | |||||
| } | |||||
| const LineSection& firstLine = subPath.getReference (0); | |||||
| int i; | |||||
| for (i = 1; i < subPath.size(); ++i) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (i); | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.lx1, l.ly1, l.lx2, l.ly2, | |||||
| l.x1, l.y1); | |||||
| lastX1 = l.lx1; | |||||
| lastY1 = l.ly1; | |||||
| lastX2 = l.lx2; | |||||
| lastY2 = l.ly2; | |||||
| } | |||||
| float lastX1 = firstLine.lx1; | |||||
| float lastY1 = firstLine.ly1; | |||||
| float lastX2 = firstLine.lx2; | |||||
| float lastY2 = firstLine.ly2; | |||||
| const LineSection& lastLine = subPath.getReference (subPath.size() - 1); | |||||
| if (isClosed) | |||||
| { | |||||
| destPath.startNewSubPath (lastX1, lastY1); | |||||
| } | |||||
| else | |||||
| { | |||||
| destPath.startNewSubPath (firstLine.rx2, firstLine.ry2); | |||||
| if (isClosed) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (0); | |||||
| addLineEnd (destPath, endStyle, | |||||
| firstLine.rx2, firstLine.ry2, | |||||
| lastX1, lastY1, | |||||
| width); | |||||
| } | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.lx1, l.ly1, l.lx2, l.ly2, | |||||
| l.x1, l.y1); | |||||
| int i; | |||||
| for (i = 1; i < subPath.size(); ++i) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (i); | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.lx1, l.ly1, l.lx2, l.ly2, | |||||
| l.x1, l.y1); | |||||
| lastX1 = l.lx1; | |||||
| lastY1 = l.ly1; | |||||
| lastX2 = l.lx2; | |||||
| lastY2 = l.ly2; | |||||
| } | |||||
| destPath.closeSubPath(); | |||||
| destPath.startNewSubPath (lastLine.rx1, lastLine.ry1); | |||||
| } | |||||
| else | |||||
| { | |||||
| destPath.lineTo (lastX2, lastY2); | |||||
| const LineSection& lastLine = subPath.getReference (subPath.size() - 1); | |||||
| addLineEnd (destPath, endStyle, | |||||
| lastX2, lastY2, | |||||
| lastLine.rx1, lastLine.ry1, | |||||
| width); | |||||
| } | |||||
| if (isClosed) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (0); | |||||
| lastX1 = lastLine.rx1; | |||||
| lastY1 = lastLine.ry1; | |||||
| lastX2 = lastLine.rx2; | |||||
| lastY2 = lastLine.ry2; | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.lx1, l.ly1, l.lx2, l.ly2, | |||||
| l.x1, l.y1); | |||||
| for (i = subPath.size() - 1; --i >= 0;) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (i); | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.rx1, l.ry1, l.rx2, l.ry2, | |||||
| l.x2, l.y2); | |||||
| lastX1 = l.rx1; | |||||
| lastY1 = l.ry1; | |||||
| lastX2 = l.rx2; | |||||
| lastY2 = l.ry2; | |||||
| } | |||||
| destPath.closeSubPath(); | |||||
| destPath.startNewSubPath (lastLine.rx1, lastLine.ry1); | |||||
| } | |||||
| else | |||||
| { | |||||
| destPath.lineTo (lastX2, lastY2); | |||||
| if (isClosed) | |||||
| { | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| lastLine.rx1, lastLine.ry1, lastLine.rx2, lastLine.ry2, | |||||
| lastLine.x2, lastLine.y2); | |||||
| } | |||||
| else | |||||
| { | |||||
| // do the last line | |||||
| destPath.lineTo (lastX2, lastY2); | |||||
| } | |||||
| addLineEnd (destPath, endStyle, | |||||
| lastX2, lastY2, | |||||
| lastLine.rx1, lastLine.ry1, | |||||
| width); | |||||
| } | |||||
| lastX1 = lastLine.rx1; | |||||
| lastY1 = lastLine.ry1; | |||||
| lastX2 = lastLine.rx2; | |||||
| lastY2 = lastLine.ry2; | |||||
| for (i = subPath.size() - 1; --i >= 0;) | |||||
| { | |||||
| const LineSection& l = subPath.getReference (i); | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| l.rx1, l.ry1, l.rx2, l.ry2, | |||||
| l.x2, l.y2); | |||||
| lastX1 = l.rx1; | |||||
| lastY1 = l.ry1; | |||||
| lastX2 = l.rx2; | |||||
| lastY2 = l.ry2; | |||||
| } | |||||
| if (isClosed) | |||||
| { | |||||
| addEdgeAndJoint (destPath, jointStyle, | |||||
| maxMiterExtensionSquared, width, | |||||
| lastX1, lastY1, lastX2, lastY2, | |||||
| lastLine.rx1, lastLine.ry1, lastLine.rx2, lastLine.ry2, | |||||
| lastLine.x2, lastLine.y2); | |||||
| } | |||||
| else | |||||
| { | |||||
| // do the last line | |||||
| destPath.lineTo (lastX2, lastY2); | |||||
| } | |||||
| destPath.closeSubPath(); | |||||
| destPath.closeSubPath(); | |||||
| } | |||||
| } | } | ||||
| void PathStrokeType::createStrokedPath (Path& destPath, | void PathStrokeType::createStrokedPath (Path& destPath, | ||||
| const Path& source, | const Path& source, | ||||
| const AffineTransform& transform, | const AffineTransform& transform, | ||||
| const float extraAccuracy) const throw() | |||||
| const float extraAccuracy) const | |||||
| { | { | ||||
| if (thickness <= 0) | if (thickness <= 0) | ||||
| { | { | ||||
| @@ -497,6 +500,7 @@ void PathStrokeType::createStrokedPath (Path& destPath, | |||||
| // left/right-hand lines along either side of it... | // left/right-hand lines along either side of it... | ||||
| PathFlatteningIterator it (*sourcePath, transform, 9.0f / extraAccuracy); | PathFlatteningIterator it (*sourcePath, transform, 9.0f / extraAccuracy); | ||||
| using namespace PathFunctions; | |||||
| Array <LineSection> subPath; | Array <LineSection> subPath; | ||||
| LineSection l; | LineSection l; | ||||
| l.x1 = 0; | l.x1 = 0; | ||||
| @@ -576,7 +580,7 @@ void PathStrokeType::createDashedStroke (Path& destPath, | |||||
| const float* dashLengths, | const float* dashLengths, | ||||
| int numDashLengths, | int numDashLengths, | ||||
| const AffineTransform& transform, | const AffineTransform& transform, | ||||
| const float extraAccuracy) const throw() | |||||
| const float extraAccuracy) const | |||||
| { | { | ||||
| if (thickness <= 0) | if (thickness <= 0) | ||||
| return; | return; | ||||
| @@ -104,7 +104,7 @@ public: | |||||
| void createStrokedPath (Path& destPath, | void createStrokedPath (Path& destPath, | ||||
| const Path& sourcePath, | const Path& sourcePath, | ||||
| const AffineTransform& transform = AffineTransform::identity, | const AffineTransform& transform = AffineTransform::identity, | ||||
| const float extraAccuracy = 1.0f) const throw(); | |||||
| const float extraAccuracy = 1.0f) const; | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -135,7 +135,7 @@ public: | |||||
| const float* dashLengths, | const float* dashLengths, | ||||
| int numDashLengths, | int numDashLengths, | ||||
| const AffineTransform& transform = AffineTransform::identity, | const AffineTransform& transform = AffineTransform::identity, | ||||
| const float extraAccuracy = 1.0f) const throw(); | |||||
| const float extraAccuracy = 1.0f) const; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the stroke thickness. */ | /** Returns the stroke thickness. */ | ||||
| @@ -412,68 +412,66 @@ struct MidiPortAndCallback | |||||
| int pendingBytes; | int pendingBytes; | ||||
| double pendingDataTime; | double pendingDataTime; | ||||
| bool active; | bool active; | ||||
| }; | |||||
| static CriticalSection callbackLock; | |||||
| static VoidArray activeCallbacks; | |||||
| static void processSysex (MidiPortAndCallback* const mpc, const uint8*& d, int& size, const double time) | |||||
| { | |||||
| if (*d == 0xf0) | |||||
| void processSysex (const uint8*& d, int& size, const double time) | |||||
| { | { | ||||
| mpc->pendingBytes = 0; | |||||
| mpc->pendingDataTime = time; | |||||
| } | |||||
| if (*d == 0xf0) | |||||
| { | |||||
| pendingBytes = 0; | |||||
| pendingDataTime = time; | |||||
| } | |||||
| mpc->pendingData.ensureSize (mpc->pendingBytes + size, false); | |||||
| uint8* totalMessage = (uint8*) mpc->pendingData.getData(); | |||||
| pendingData.ensureSize (pendingBytes + size, false); | |||||
| uint8* totalMessage = (uint8*) pendingData.getData(); | |||||
| uint8* dest = totalMessage + mpc->pendingBytes; | |||||
| uint8* dest = totalMessage + pendingBytes; | |||||
| while (size > 0) | |||||
| { | |||||
| if (mpc->pendingBytes > 0 && *d >= 0x80) | |||||
| while (size > 0) | |||||
| { | { | ||||
| if (*d >= 0xfa || *d == 0xf8) | |||||
| if (pendingBytes > 0 && *d >= 0x80) | |||||
| { | { | ||||
| mpc->callback->handleIncomingMidiMessage (mpc->input, MidiMessage (*d, time)); | |||||
| ++d; | |||||
| --size; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (*d == 0xf7) | |||||
| if (*d >= 0xfa || *d == 0xf8) | |||||
| { | { | ||||
| *dest++ = *d++; | |||||
| mpc->pendingBytes++; | |||||
| callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); | |||||
| ++d; | |||||
| --size; | --size; | ||||
| } | } | ||||
| else | |||||
| { | |||||
| if (*d == 0xf7) | |||||
| { | |||||
| *dest++ = *d++; | |||||
| pendingBytes++; | |||||
| --size; | |||||
| } | |||||
| break; | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| *dest++ = *d++; | |||||
| pendingBytes++; | |||||
| --size; | |||||
| } | } | ||||
| } | } | ||||
| if (totalMessage [pendingBytes - 1] == 0xf7) | |||||
| { | |||||
| callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); | |||||
| pendingBytes = 0; | |||||
| } | |||||
| else | else | ||||
| { | { | ||||
| *dest++ = *d++; | |||||
| mpc->pendingBytes++; | |||||
| --size; | |||||
| callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); | |||||
| } | } | ||||
| } | } | ||||
| }; | |||||
| if (totalMessage [mpc->pendingBytes - 1] == 0xf7) | |||||
| { | |||||
| mpc->callback->handleIncomingMidiMessage (mpc->input, MidiMessage (totalMessage, | |||||
| mpc->pendingBytes, | |||||
| mpc->pendingDataTime)); | |||||
| mpc->pendingBytes = 0; | |||||
| } | |||||
| else | |||||
| { | |||||
| mpc->callback->handlePartialSysexMessage (mpc->input, | |||||
| totalMessage, | |||||
| mpc->pendingBytes, | |||||
| mpc->pendingDataTime); | |||||
| } | |||||
| namespace CoreMidiCallbacks | |||||
| { | |||||
| static CriticalSection callbackLock; | |||||
| static VoidArray activeCallbacks; | |||||
| } | } | ||||
| static void midiInputProc (const MIDIPacketList* pktlist, | static void midiInputProc (const MIDIPacketList* pktlist, | ||||
| @@ -484,9 +482,9 @@ static void midiInputProc (const MIDIPacketList* pktlist, | |||||
| const double originalTime = time; | const double originalTime = time; | ||||
| MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; | MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; | ||||
| const ScopedLock sl (callbackLock); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| if (activeCallbacks.contains (mpc) && mpc->active) | |||||
| if (CoreMidiCallbacks::activeCallbacks.contains (mpc) && mpc->active) | |||||
| { | { | ||||
| const MIDIPacket* packet = &pktlist->packet[0]; | const MIDIPacket* packet = &pktlist->packet[0]; | ||||
| @@ -501,7 +499,7 @@ static void midiInputProc (const MIDIPacketList* pktlist, | |||||
| if (mpc->pendingBytes > 0 || d[0] == 0xf0) | if (mpc->pendingBytes > 0 || d[0] == 0xf0) | ||||
| { | { | ||||
| processSysex (mpc, d, size, time); | |||||
| mpc->processSysex (d, size, time); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -564,8 +562,8 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) | |||||
| mpc->input = mi; | mpc->input = mi; | ||||
| mi->internal = (void*) mpc; | mi->internal = (void*) mpc; | ||||
| const ScopedLock sl (callbackLock); | |||||
| activeCallbacks.add (mpc.release()); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| CoreMidiCallbacks::activeCallbacks.add (mpc.release()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -604,8 +602,8 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba | |||||
| mpc->input = mi; | mpc->input = mi; | ||||
| mi->internal = (void*) mpc; | mi->internal = (void*) mpc; | ||||
| const ScopedLock sl (callbackLock); | |||||
| activeCallbacks.add (mpc.release()); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| CoreMidiCallbacks::activeCallbacks.add (mpc.release()); | |||||
| } | } | ||||
| CFRelease (name); | CFRelease (name); | ||||
| @@ -625,8 +623,8 @@ MidiInput::~MidiInput() | |||||
| mpc->active = false; | mpc->active = false; | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | |||||
| activeCallbacks.removeValue (mpc); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| CoreMidiCallbacks::activeCallbacks.removeValue (mpc); | |||||
| } | } | ||||
| if (mpc->portAndEndpoint->port != 0) | if (mpc->portAndEndpoint->port != 0) | ||||
| @@ -638,13 +636,13 @@ MidiInput::~MidiInput() | |||||
| void MidiInput::start() | void MidiInput::start() | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| ((MidiPortAndCallback*) internal)->active = true; | ((MidiPortAndCallback*) internal)->active = true; | ||||
| } | } | ||||
| void MidiInput::stop() | void MidiInput::stop() | ||||
| { | { | ||||
| const ScopedLock sl (callbackLock); | |||||
| const ScopedLock sl (CoreMidiCallbacks::callbackLock); | |||||
| ((MidiPortAndCallback*) internal)->active = false; | ((MidiPortAndCallback*) internal)->active = false; | ||||
| } | } | ||||
| @@ -209,6 +209,40 @@ public: | |||||
| virtual NSRect constrainRect (NSRect r); | virtual NSRect constrainRect (NSRect r); | ||||
| static void showArrowCursorIfNeeded(); | static void showArrowCursorIfNeeded(); | ||||
| static void updateModifiers (NSEvent* e); | |||||
| static void updateKeysDown (NSEvent* ev, bool isKeyDown); | |||||
| static int getKeyCodeFromEvent (NSEvent* ev) | |||||
| { | |||||
| const String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); | |||||
| int keyCode = unmodified[0]; | |||||
| if (keyCode == 0x19) // (backwards-tab) | |||||
| keyCode = '\t'; | |||||
| else if (keyCode == 0x03) // (enter) | |||||
| keyCode = '\r'; | |||||
| return keyCode; | |||||
| } | |||||
| static int64 getMouseTime (NSEvent* e) | |||||
| { | |||||
| return (Time::currentTimeMillis() - Time::getMillisecondCounter()) | |||||
| + (int64) ([e timestamp] * 1000.0); | |||||
| } | |||||
| static const Point<int> getMousePos (NSEvent* e, NSView* view) | |||||
| { | |||||
| NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; | |||||
| return Point<int> (roundToInt (p.x), roundToInt ([view frame].size.height - p.y)); | |||||
| } | |||||
| static int getModifierForButtonNumber (const NSInteger num) | |||||
| { | |||||
| return num == 0 ? ModifierKeys::leftButtonModifier | |||||
| : (num == 1 ? ModifierKeys::rightButtonModifier | |||||
| : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| virtual void viewFocusGain(); | virtual void viewFocusGain(); | ||||
| @@ -724,22 +758,9 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() | |||||
| return false; | return false; | ||||
| } | } | ||||
| static int getKeyCodeFromEvent (NSEvent* ev) | |||||
| { | |||||
| const String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); | |||||
| int keyCode = unmodified[0]; | |||||
| if (keyCode == 0x19) // (backwards-tab) | |||||
| keyCode = '\t'; | |||||
| else if (keyCode == 0x03) // (enter) | |||||
| keyCode = '\r'; | |||||
| return keyCode; | |||||
| } | |||||
| static int currentModifiers = 0; | static int currentModifiers = 0; | ||||
| static void updateModifiers (NSEvent* e) | |||||
| void NSViewComponentPeer::updateModifiers (NSEvent* e) | |||||
| { | { | ||||
| int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier | int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier | ||||
| | ModifierKeys::altModifier | ModifierKeys::commandModifier); | | ModifierKeys::altModifier | ModifierKeys::commandModifier); | ||||
| @@ -759,7 +780,7 @@ static void updateModifiers (NSEvent* e) | |||||
| currentModifiers = m; | currentModifiers = m; | ||||
| } | } | ||||
| static void updateKeysDown (NSEvent* ev, bool isKeyDown) | |||||
| void NSViewComponentPeer::updateKeysDown (NSEvent* ev, bool isKeyDown) | |||||
| { | { | ||||
| updateModifiers (ev); | updateModifiers (ev); | ||||
| int keyCode = getKeyCodeFromEvent (ev); | int keyCode = getKeyCodeFromEvent (ev); | ||||
| @@ -783,25 +804,6 @@ void ModifierKeys::updateCurrentModifiers() throw() | |||||
| currentModifierFlags = currentModifiers; | currentModifierFlags = currentModifiers; | ||||
| } | } | ||||
| static int64 getMouseTime (NSEvent* e) | |||||
| { | |||||
| return (Time::currentTimeMillis() - Time::getMillisecondCounter()) | |||||
| + (int64) ([e timestamp] * 1000.0); | |||||
| } | |||||
| static const Point<int> getMousePos (NSEvent* e, NSView* view) | |||||
| { | |||||
| NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; | |||||
| return Point<int> (roundToInt (p.x), roundToInt ([view frame].size.height - p.y)); | |||||
| } | |||||
| static int getModifierForButtonNumber (const NSInteger num) | |||||
| { | |||||
| return num == 0 ? ModifierKeys::leftButtonModifier | |||||
| : (num == 1 ? ModifierKeys::rightButtonModifier | |||||
| : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| NSViewComponentPeer::NSViewComponentPeer (Component* const component_, | NSViewComponentPeer::NSViewComponentPeer (Component* const component_, | ||||
| const int windowStyleFlags, | const int windowStyleFlags, | ||||
| @@ -150,106 +150,114 @@ XmlElement::~XmlElement() throw() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static bool isLegalXmlChar (const juce_wchar character) | |||||
| namespace XmlOutputFunctions | |||||
| { | { | ||||
| if ((character >= 'a' && character <= 'z') | |||||
| || (character >= 'A' && character <= 'Z') | |||||
| || (character >= '0' && character <= '9')) | |||||
| return true; | |||||
| const char* t = " .,;:-()_+=?!'#@[]/\\*%~{}"; | |||||
| do | |||||
| /*static bool isLegalXmlCharSlow (const juce_wchar character) throw() | |||||
| { | { | ||||
| if (((juce_wchar) (uint8) *t) == character) | |||||
| if ((character >= 'a' && character <= 'z') | |||||
| || (character >= 'A' && character <= 'Z') | |||||
| || (character >= '0' && character <= '9')) | |||||
| return true; | return true; | ||||
| } | |||||
| while (*++t != 0); | |||||
| return false; | |||||
| } | |||||
| const char* t = " .,;:-()_+=?!'#@[]/\\*%~{}"; | |||||
| static void escapeIllegalXmlChars (OutputStream& outputStream, | |||||
| const String& text, | |||||
| const bool changeNewLines) throw() | |||||
| { | |||||
| const juce_wchar* t = (const juce_wchar*) text; | |||||
| do | |||||
| { | |||||
| if (((juce_wchar) (uint8) *t) == character) | |||||
| return true; | |||||
| } | |||||
| while (*++t != 0); | |||||
| for (;;) | |||||
| return false; | |||||
| } | |||||
| static void generateLegalCharConstants() | |||||
| { | { | ||||
| const juce_wchar character = *t++; | |||||
| uint8 n[32]; | |||||
| zerostruct (n); | |||||
| for (int i = 0; i < 256; ++i) | |||||
| if (isLegalXmlCharSlow (i)) | |||||
| n[i >> 3] |= (1 << (i & 7)); | |||||
| if (character == 0) | |||||
| { | |||||
| break; | |||||
| } | |||||
| else if (isLegalXmlChar (character)) | |||||
| { | |||||
| outputStream.writeByte ((char) character); | |||||
| } | |||||
| else | |||||
| { | |||||
| switch (character) | |||||
| { | |||||
| case '&': | |||||
| outputStream.write ("&", 5); | |||||
| break; | |||||
| String s; | |||||
| for (int i = 0; i < 32; ++i) | |||||
| s << (int) n[i] << ", "; | |||||
| case '"': | |||||
| outputStream.write (""", 6); | |||||
| break; | |||||
| DBG (s); | |||||
| }*/ | |||||
| case '>': | |||||
| outputStream.write (">", 4); | |||||
| break; | |||||
| static bool isLegalXmlChar (const uint32 c) throw() | |||||
| { | |||||
| static const unsigned char legalChars[] = { 0, 0, 0, 0, 171, 255, 255, 175, 255, 255, 255, 191, 254, 255, 255, 111 }; | |||||
| case '<': | |||||
| outputStream.write ("<", 4); | |||||
| break; | |||||
| return c < sizeof (legalChars) * 8 | |||||
| && (legalChars [c >> 3] & (1 << (c & 7))) != 0; | |||||
| } | |||||
| case '\n': | |||||
| if (changeNewLines) | |||||
| outputStream.write (" ", 5); | |||||
| else | |||||
| outputStream.writeByte ((char) character); | |||||
| static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines) | |||||
| { | |||||
| const juce_wchar* t = (const juce_wchar*) text; | |||||
| for (;;) | |||||
| { | |||||
| const juce_wchar character = *t++; | |||||
| if (character == 0) | |||||
| { | |||||
| break; | break; | ||||
| } | |||||
| else if (isLegalXmlChar ((uint32) character)) | |||||
| { | |||||
| outputStream << (char) character; | |||||
| } | |||||
| else | |||||
| { | |||||
| switch (character) | |||||
| { | |||||
| case '&': outputStream << "&"; break; | |||||
| case '"': outputStream << """; break; | |||||
| case '>': outputStream << ">"; break; | |||||
| case '<': outputStream << "<"; break; | |||||
| case '\n': | |||||
| if (changeNewLines) | |||||
| outputStream << " "; | |||||
| else | |||||
| outputStream << (char) character; | |||||
| case '\r': | |||||
| if (changeNewLines) | |||||
| outputStream.write (" ", 5); | |||||
| else | |||||
| outputStream.writeByte ((char) character); | |||||
| break; | |||||
| break; | |||||
| case '\r': | |||||
| if (changeNewLines) | |||||
| outputStream << " "; | |||||
| else | |||||
| outputStream << (char) character; | |||||
| default: | |||||
| { | |||||
| String encoded (T("&#")); | |||||
| encoded << String ((int) (unsigned int) character).trim() | |||||
| << T(';'); | |||||
| break; | |||||
| outputStream.write ((const char*) encoded, encoded.length()); | |||||
| default: | |||||
| outputStream << "&#" << ((int) (unsigned int) character) << ';'; | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| static void writeSpaces (OutputStream& out, int numSpaces) throw() | |||||
| { | |||||
| if (numSpaces > 0) | |||||
| static void writeSpaces (OutputStream& out, int numSpaces) throw() | |||||
| { | { | ||||
| const char* const blanks = " "; | |||||
| const int blankSize = (int) sizeof (blanks) - 1; | |||||
| while (numSpaces > blankSize) | |||||
| if (numSpaces > 0) | |||||
| { | { | ||||
| out.write (blanks, blankSize); | |||||
| numSpaces -= blankSize; | |||||
| } | |||||
| const char* const blanks = " "; | |||||
| const int blankSize = (int) sizeof (blanks) - 1; | |||||
| while (numSpaces > blankSize) | |||||
| { | |||||
| out.write (blanks, blankSize); | |||||
| numSpaces -= blankSize; | |||||
| } | |||||
| out.write (blanks, numSpaces); | |||||
| out.write (blanks, numSpaces); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -257,6 +265,7 @@ void XmlElement::writeElementAsText (OutputStream& outputStream, | |||||
| const int indentationLevel, | const int indentationLevel, | ||||
| const int lineWrapLength) const throw() | const int lineWrapLength) const throw() | ||||
| { | { | ||||
| using namespace XmlOutputFunctions; | |||||
| writeSpaces (outputStream, indentationLevel); | writeSpaces (outputStream, indentationLevel); | ||||
| if (! isTextElement()) | if (! isTextElement()) | ||||