| @@ -4908,7 +4908,7 @@ END_JUCE_NAMESPACE | |||
| /*** Start of inlined file: juce_Expression.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| class Expression::Term : public ReferenceCountedObject | |||
| class Expression::Term : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| Term() {} | |||
| @@ -22501,7 +22501,11 @@ AudioThumbnail::~AudioThumbnail() | |||
| void AudioThumbnail::clear() | |||
| { | |||
| source = nullptr; | |||
| clearChannelData(); | |||
| } | |||
| void AudioThumbnail::clearChannelData() | |||
| { | |||
| const ScopedLock sl (lock); | |||
| window->invalidate(); | |||
| channels.clear(); | |||
| @@ -22531,7 +22535,7 @@ void AudioThumbnail::createChannels (const int length) | |||
| void AudioThumbnail::loadFrom (InputStream& rawInput) | |||
| { | |||
| clear(); | |||
| clearChannelData(); | |||
| BufferedInputStream input (rawInput, 4096); | |||
| @@ -86247,7 +86251,7 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE (TransformedImageFillEdgeTableRenderer); | |||
| }; | |||
| class ClipRegionBase : public ReferenceCountedObject | |||
| class ClipRegionBase : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| ClipRegionBase() {} | |||
| @@ -91982,33 +91986,40 @@ END_JUCE_NAMESPACE | |||
| /*** Start of inlined file: juce_GlyphArrangement.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| PositionedGlyph::PositionedGlyph (const float x_, const float y_, const float w_, const Font& font_, | |||
| const juce_wchar character_, const int glyph_) | |||
| : x (x_), | |||
| y (y_), | |||
| w (w_), | |||
| font (font_), | |||
| character (character_), | |||
| glyph (glyph_) | |||
| PositionedGlyph::PositionedGlyph (const Font& font_, const juce_wchar character_, const int glyph_, | |||
| const float x_, const float y_, const float w_, const bool whitespace_) | |||
| : font (font_), character (character_), glyph (glyph_), | |||
| x (x_), y (y_), w (w_), whitespace (whitespace_) | |||
| { | |||
| } | |||
| PositionedGlyph::PositionedGlyph (const PositionedGlyph& other) | |||
| : x (other.x), | |||
| y (other.y), | |||
| w (other.w), | |||
| font (other.font), | |||
| character (other.character), | |||
| glyph (other.glyph) | |||
| : font (other.font), character (other.character), glyph (other.glyph), | |||
| x (other.x), y (other.y), w (other.w), whitespace (other.whitespace) | |||
| { | |||
| } | |||
| PositionedGlyph::~PositionedGlyph() {} | |||
| PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other) | |||
| { | |||
| font = other.font; | |||
| character = other.character; | |||
| glyph = other.glyph; | |||
| x = other.x; | |||
| y = other.y; | |||
| w = other.w; | |||
| whitespace = other.whitespace; | |||
| return *this; | |||
| } | |||
| void PositionedGlyph::draw (const Graphics& g) const | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| g.getInternalContext()->setFont (font); | |||
| g.getInternalContext()->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| } | |||
| } | |||
| @@ -92017,9 +92028,10 @@ void PositionedGlyph::draw (const Graphics& g, | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| g.getInternalContext()->setFont (font); | |||
| g.getInternalContext()->drawGlyph (glyph, AffineTransform::translation (x, y) | |||
| .followedBy (transform)); | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y) | |||
| .followedBy (transform)); | |||
| } | |||
| } | |||
| @@ -92112,6 +92124,11 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) | |||
| glyphs.addCopiesOf (other.glyphs); | |||
| } | |||
| void GlyphArrangement::addGlyph (const PositionedGlyph& glyph) | |||
| { | |||
| glyphs.add (new PositionedGlyph (glyph)); | |||
| } | |||
| void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) | |||
| { | |||
| glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num); | |||
| @@ -92129,7 +92146,7 @@ void GlyphArrangement::addLineOfText (const Font& font, | |||
| void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| const String& text, | |||
| float xOffset, | |||
| const float xOffset, | |||
| const float yOffset, | |||
| const float maxWidthPixels, | |||
| const bool useEllipsis) | |||
| @@ -92140,6 +92157,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| Array <float> xOffsets; | |||
| font.getGlyphPositions (text, newGlyphs, xOffsets); | |||
| const int textLen = newGlyphs.size(); | |||
| glyphs.ensureStorageAllocated (glyphs.size() + textLen); | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| @@ -92158,8 +92176,12 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| } | |||
| else | |||
| { | |||
| glyphs.add (new PositionedGlyph (xOffset + thisX, yOffset, nextX - thisX, | |||
| font, t.getAndAdvance(), newGlyphs.getUnchecked(i))); | |||
| const bool isWhitespace = t.isWhitespace(); | |||
| glyphs.add (new PositionedGlyph (font, t.getAndAdvance(), | |||
| newGlyphs.getUnchecked(i), | |||
| xOffset + thisX, yOffset, | |||
| nextX - thisX, isWhitespace)); | |||
| } | |||
| } | |||
| } | |||
| @@ -92194,8 +92216,8 @@ int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||
| for (int i = 3; --i >= 0;) | |||
| { | |||
| glyphs.insert (endIndex++, new PositionedGlyph (xOffset, yOffset, dx, | |||
| font, '.', dotGlyphs.getFirst())); | |||
| glyphs.insert (endIndex++, new PositionedGlyph (font, '.', dotGlyphs.getFirst(), | |||
| xOffset, yOffset, dx, false)); | |||
| --numDeleted; | |||
| xOffset += dx; | |||
| @@ -7412,6 +7412,24 @@ public: | |||
| } | |||
| } | |||
| /** This will enlarge or shrink the array to the given number of elements, by adding | |||
| or removing items from its end. | |||
| If the array is smaller than the given target size, empty elements will be appended | |||
| until its size is as specified. If its size is larger than the target, items will be | |||
| removed from its end to shorten it. | |||
| */ | |||
| void resize (const int targetNumItems) | |||
| { | |||
| jassert (targetNumItems >= 0); | |||
| const int numToAdd = targetNumItems - numUsed; | |||
| if (numToAdd > 0) | |||
| insertMultiple (numUsed, ElementType(), numToAdd); | |||
| else if (numToAdd < 0) | |||
| removeRange (targetNumItems, -numToAdd); | |||
| } | |||
| /** Inserts a new element into the array, assuming that the array is sorted. | |||
| This will use a comparator to find the position at which the new element | |||
| @@ -9059,7 +9077,11 @@ private: | |||
| Once a new ReferenceCountedObject has been assigned to a pointer, be | |||
| careful not to delete the object manually. | |||
| @see ReferenceCountedObjectPtr, ReferenceCountedArray | |||
| This class uses an Atomic<int> value to hold the reference count, so that it | |||
| the pointers can be passed between threads safely. For a faster but non-thread-safe | |||
| version, use SingleThreadedReferenceCountedObject instead. | |||
| @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject | |||
| */ | |||
| class JUCE_API ReferenceCountedObject | |||
| { | |||
| @@ -9088,10 +9110,7 @@ public: | |||
| } | |||
| /** Returns the object's current reference count. */ | |||
| inline int getReferenceCount() const noexcept | |||
| { | |||
| return refCount.get(); | |||
| } | |||
| inline int getReferenceCount() const noexcept { return refCount.get(); } | |||
| protected: | |||
| @@ -9112,6 +9131,62 @@ private: | |||
| Atomic <int> refCount; | |||
| }; | |||
| /** | |||
| Adds reference-counting to an object. | |||
| This is efectively a version of the ReferenceCountedObject class, but which | |||
| uses a non-atomic counter, and so is not thread-safe (but which will be more | |||
| efficient). | |||
| For more details on how to use it, see the ReferenceCountedObject class notes. | |||
| @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray | |||
| */ | |||
| class JUCE_API SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| /** Increments the object's reference count. | |||
| This is done automatically by the smart pointer, but is public just | |||
| in case it's needed for nefarious purposes. | |||
| */ | |||
| inline void incReferenceCount() noexcept | |||
| { | |||
| ++refCount; | |||
| } | |||
| /** Decreases the object's reference count. | |||
| If the count gets to zero, the object will be deleted. | |||
| */ | |||
| inline void decReferenceCount() noexcept | |||
| { | |||
| jassert (getReferenceCount() > 0); | |||
| if (--refCount == 0) | |||
| delete this; | |||
| } | |||
| /** Returns the object's current reference count. */ | |||
| inline int getReferenceCount() const noexcept { return refCount; } | |||
| protected: | |||
| /** Creates the reference-counted object (with an initial ref count of zero). */ | |||
| SingleThreadedReferenceCountedObject() : refCount (0) {} | |||
| /** Destructor. */ | |||
| virtual ~SingleThreadedReferenceCountedObject() | |||
| { | |||
| // it's dangerous to delete an object that's still referenced by something else! | |||
| jassert (getReferenceCount() == 0); | |||
| } | |||
| private: | |||
| int refCount; | |||
| }; | |||
| /** | |||
| A smart-pointer class which points to a reference-counted object. | |||
| @@ -16262,7 +16337,7 @@ public: | |||
| of a ValueSource object. If you're feeling adventurous, you can create your own custom | |||
| ValueSource classes to allow Value objects to represent your own custom data items. | |||
| */ | |||
| class JUCE_API ValueSource : public ReferenceCountedObject, | |||
| class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject, | |||
| public AsyncUpdater | |||
| { | |||
| public: | |||
| @@ -17147,14 +17222,11 @@ public: | |||
| private: | |||
| class SetPropertyAction; | |||
| friend class SetPropertyAction; | |||
| class AddOrRemoveChildAction; | |||
| friend class AddOrRemoveChildAction; | |||
| class MoveChildAction; | |||
| friend class MoveChildAction; | |||
| class SetPropertyAction; friend class SetPropertyAction; | |||
| class AddOrRemoveChildAction; friend class AddOrRemoveChildAction; | |||
| class MoveChildAction; friend class MoveChildAction; | |||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||
| class JUCE_API SharedObject : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| explicit SharedObject (const Identifier& type); | |||
| @@ -21560,7 +21632,7 @@ private: | |||
| @see WeakReference::Master | |||
| */ | |||
| template <class ObjectType> | |||
| template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject> | |||
| class WeakReference | |||
| { | |||
| public: | |||
| @@ -21607,7 +21679,7 @@ public: | |||
| in your code! | |||
| @see WeakReference | |||
| */ | |||
| class SharedPointer : public ReferenceCountedObject | |||
| class SharedPointer : public ReferenceCountingType | |||
| { | |||
| public: | |||
| explicit SharedPointer (ObjectType* const owner_) noexcept : owner (owner_) {} | |||
| @@ -24999,7 +25071,7 @@ class AffineTransform; | |||
| @see CustomTypeface, Font | |||
| */ | |||
| class JUCE_API Typeface : public ReferenceCountedObject | |||
| class JUCE_API Typeface : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| @@ -25403,7 +25475,7 @@ private: | |||
| friend class FontGlyphAlphaMap; | |||
| friend class TypefaceCache; | |||
| class SharedFontInternal : public ReferenceCountedObject | |||
| class SharedFontInternal : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedFontInternal (float height, int styleFlags) noexcept; | |||
| @@ -37453,6 +37525,7 @@ private: | |||
| double sampleRate; | |||
| CriticalSection lock; | |||
| void clearChannelData(); | |||
| bool setDataSource (LevelDataSource* newSource); | |||
| void setLevels (const MinMaxValue* const* values, int thumbIndex, int numChans, int numValues); | |||
| void createChannels (int length); | |||
| @@ -44045,7 +44118,7 @@ public: | |||
| @see PopupMenu::addCustomItem | |||
| */ | |||
| class JUCE_API CustomComponent : public Component, | |||
| public ReferenceCountedObject | |||
| public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| /** Creates a custom item. | |||
| @@ -57363,25 +57436,33 @@ private: | |||
| A glyph from a particular font, with a particular size, style, | |||
| typeface and position. | |||
| You should rarely need to use this class directly - for most purposes, the | |||
| GlyphArrangement class will do what you need for text layout. | |||
| @see GlyphArrangement, Font | |||
| */ | |||
| class JUCE_API PositionedGlyph | |||
| { | |||
| public: | |||
| PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber, | |||
| float anchorX, float baselineY, float width, bool isWhitespace); | |||
| PositionedGlyph (const PositionedGlyph& other); | |||
| PositionedGlyph& operator= (const PositionedGlyph& other); | |||
| ~PositionedGlyph(); | |||
| /** Returns the character the glyph represents. */ | |||
| juce_wchar getCharacter() const { return character; } | |||
| juce_wchar getCharacter() const noexcept { return character; } | |||
| /** Checks whether the glyph is actually empty. */ | |||
| bool isWhitespace() const { return CharacterFunctions::isWhitespace (character); } | |||
| bool isWhitespace() const noexcept { return whitespace; } | |||
| /** Returns the position of the glyph's left-hand edge. */ | |||
| float getLeft() const { return x; } | |||
| float getLeft() const noexcept { return x; } | |||
| /** Returns the position of the glyph's right-hand edge. */ | |||
| float getRight() const { return x + w; } | |||
| float getRight() const noexcept { return x + w; } | |||
| /** Returns the y position of the glyph's baseline. */ | |||
| float getBaselineY() const { return y; } | |||
| float getBaselineY() const noexcept { return y; } | |||
| /** Returns the y position of the top of the glyph. */ | |||
| float getTop() const { return y - font.getAscent(); } | |||
| /** Returns the y position of the bottom of the glyph. */ | |||
| @@ -57410,12 +57491,12 @@ public: | |||
| private: | |||
| friend class GlyphArrangement; | |||
| float x, y, w; | |||
| Font font; | |||
| juce_wchar character; | |||
| int glyph; | |||
| float x, y, w; | |||
| bool whitespace; | |||
| PositionedGlyph (float x, float y, float w, const Font& font, juce_wchar character, int glyph); | |||
| JUCE_LEAK_DETECTOR (PositionedGlyph); | |||
| }; | |||
| @@ -57439,7 +57520,6 @@ public: | |||
| GlyphArrangement (const GlyphArrangement& other); | |||
| /** Copies another arrangement onto this one. | |||
| To add another arrangement without clearing this one, use addGlyphArrangement(). | |||
| */ | |||
| GlyphArrangement& operator= (const GlyphArrangement& other); | |||
| @@ -57530,6 +57610,9 @@ public: | |||
| /** Appends another glyph arrangement to this one. */ | |||
| void addGlyphArrangement (const GlyphArrangement& other); | |||
| /** Appends a custom glyph to the arrangement. */ | |||
| void addGlyph (const PositionedGlyph& glyph); | |||
| /** Draws this glyph arrangement to a graphics context. | |||
| This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&) | |||
| @@ -57611,9 +57694,9 @@ private: | |||
| OwnedArray <PositionedGlyph> glyphs; | |||
| int insertEllipsis (const Font& font, float maxXPos, int startIndex, int endIndex); | |||
| int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||
| const Justification& justification, float minimumHorizontalScale); | |||
| 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&, | |||
| const Justification&, float minimumHorizontalScale); | |||
| void spreadOutLine (int start, int numGlyphs, float targetWidth); | |||
| JUCE_LEAK_DETECTOR (GlyphArrangement); | |||
| @@ -541,7 +541,11 @@ AudioThumbnail::~AudioThumbnail() | |||
| void AudioThumbnail::clear() | |||
| { | |||
| source = nullptr; | |||
| clearChannelData(); | |||
| } | |||
| void AudioThumbnail::clearChannelData() | |||
| { | |||
| const ScopedLock sl (lock); | |||
| window->invalidate(); | |||
| channels.clear(); | |||
| @@ -572,7 +576,7 @@ void AudioThumbnail::createChannels (const int length) | |||
| //============================================================================== | |||
| void AudioThumbnail::loadFrom (InputStream& rawInput) | |||
| { | |||
| clear(); | |||
| clearChannelData(); | |||
| BufferedInputStream input (rawInput, 4096); | |||
| @@ -227,6 +227,7 @@ private: | |||
| double sampleRate; | |||
| CriticalSection lock; | |||
| void clearChannelData(); | |||
| bool setDataSource (LevelDataSource* newSource); | |||
| void setLevels (const MinMaxValue* const* values, int thumbIndex, int numChans, int numValues); | |||
| void createChannels (int length); | |||
| @@ -594,6 +594,24 @@ public: | |||
| } | |||
| } | |||
| /** This will enlarge or shrink the array to the given number of elements, by adding | |||
| or removing items from its end. | |||
| If the array is smaller than the given target size, empty elements will be appended | |||
| until its size is as specified. If its size is larger than the target, items will be | |||
| removed from its end to shorten it. | |||
| */ | |||
| void resize (const int targetNumItems) | |||
| { | |||
| jassert (targetNumItems >= 0); | |||
| const int numToAdd = targetNumItems - numUsed; | |||
| if (numToAdd > 0) | |||
| insertMultiple (numUsed, ElementType(), numToAdd); | |||
| else if (numToAdd < 0) | |||
| removeRange (targetNumItems, -numToAdd); | |||
| } | |||
| /** Inserts a new element into the array, assuming that the array is sorted. | |||
| This will use a comparator to find the position at which the new element | |||
| @@ -170,7 +170,7 @@ public: | |||
| of a ValueSource object. If you're feeling adventurous, you can create your own custom | |||
| ValueSource classes to allow Value objects to represent your own custom data items. | |||
| */ | |||
| class JUCE_API ValueSource : public ReferenceCountedObject, | |||
| class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject, | |||
| public AsyncUpdater | |||
| { | |||
| public: | |||
| @@ -466,14 +466,11 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| class SetPropertyAction; | |||
| friend class SetPropertyAction; | |||
| class AddOrRemoveChildAction; | |||
| friend class AddOrRemoveChildAction; | |||
| class MoveChildAction; | |||
| friend class MoveChildAction; | |||
| class JUCE_API SharedObject : public ReferenceCountedObject | |||
| class SetPropertyAction; friend class SetPropertyAction; | |||
| class AddOrRemoveChildAction; friend class AddOrRemoveChildAction; | |||
| class MoveChildAction; friend class MoveChildAction; | |||
| class JUCE_API SharedObject : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| explicit SharedObject (const Identifier& type); | |||
| @@ -415,7 +415,7 @@ public: | |||
| @see PopupMenu::addCustomItem | |||
| */ | |||
| class JUCE_API CustomComponent : public Component, | |||
| public ReferenceCountedObject | |||
| public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| /** Creates a custom item. | |||
| @@ -1018,7 +1018,7 @@ private: | |||
| }; | |||
| //============================================================================== | |||
| class ClipRegionBase : public ReferenceCountedObject | |||
| class ClipRegionBase : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| ClipRegionBase() {} | |||
| @@ -364,7 +364,7 @@ private: | |||
| friend class FontGlyphAlphaMap; | |||
| friend class TypefaceCache; | |||
| class SharedFontInternal : public ReferenceCountedObject | |||
| class SharedFontInternal : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| SharedFontInternal (float height, int styleFlags) noexcept; | |||
| @@ -34,33 +34,40 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| PositionedGlyph::PositionedGlyph (const float x_, const float y_, const float w_, const Font& font_, | |||
| const juce_wchar character_, const int glyph_) | |||
| : x (x_), | |||
| y (y_), | |||
| w (w_), | |||
| font (font_), | |||
| character (character_), | |||
| glyph (glyph_) | |||
| PositionedGlyph::PositionedGlyph (const Font& font_, const juce_wchar character_, const int glyph_, | |||
| const float x_, const float y_, const float w_, const bool whitespace_) | |||
| : font (font_), character (character_), glyph (glyph_), | |||
| x (x_), y (y_), w (w_), whitespace (whitespace_) | |||
| { | |||
| } | |||
| PositionedGlyph::PositionedGlyph (const PositionedGlyph& other) | |||
| : x (other.x), | |||
| y (other.y), | |||
| w (other.w), | |||
| font (other.font), | |||
| character (other.character), | |||
| glyph (other.glyph) | |||
| : font (other.font), character (other.character), glyph (other.glyph), | |||
| x (other.x), y (other.y), w (other.w), whitespace (other.whitespace) | |||
| { | |||
| } | |||
| PositionedGlyph::~PositionedGlyph() {} | |||
| PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other) | |||
| { | |||
| font = other.font; | |||
| character = other.character; | |||
| glyph = other.glyph; | |||
| x = other.x; | |||
| y = other.y; | |||
| w = other.w; | |||
| whitespace = other.whitespace; | |||
| return *this; | |||
| } | |||
| void PositionedGlyph::draw (const Graphics& g) const | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| g.getInternalContext()->setFont (font); | |||
| g.getInternalContext()->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| } | |||
| } | |||
| @@ -69,9 +76,10 @@ void PositionedGlyph::draw (const Graphics& g, | |||
| { | |||
| if (! isWhitespace()) | |||
| { | |||
| g.getInternalContext()->setFont (font); | |||
| g.getInternalContext()->drawGlyph (glyph, AffineTransform::translation (x, y) | |||
| .followedBy (transform)); | |||
| LowLevelGraphicsContext* const context = g.getInternalContext(); | |||
| context->setFont (font); | |||
| context->drawGlyph (glyph, AffineTransform::translation (x, y) | |||
| .followedBy (transform)); | |||
| } | |||
| } | |||
| @@ -168,6 +176,11 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) | |||
| glyphs.addCopiesOf (other.glyphs); | |||
| } | |||
| void GlyphArrangement::addGlyph (const PositionedGlyph& glyph) | |||
| { | |||
| glyphs.add (new PositionedGlyph (glyph)); | |||
| } | |||
| void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) | |||
| { | |||
| glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num); | |||
| @@ -186,7 +199,7 @@ void GlyphArrangement::addLineOfText (const Font& font, | |||
| void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| const String& text, | |||
| float xOffset, | |||
| const float xOffset, | |||
| const float yOffset, | |||
| const float maxWidthPixels, | |||
| const bool useEllipsis) | |||
| @@ -197,6 +210,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| Array <float> xOffsets; | |||
| font.getGlyphPositions (text, newGlyphs, xOffsets); | |||
| const int textLen = newGlyphs.size(); | |||
| glyphs.ensureStorageAllocated (glyphs.size() + textLen); | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| @@ -215,8 +229,12 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, | |||
| } | |||
| else | |||
| { | |||
| glyphs.add (new PositionedGlyph (xOffset + thisX, yOffset, nextX - thisX, | |||
| font, t.getAndAdvance(), newGlyphs.getUnchecked(i))); | |||
| const bool isWhitespace = t.isWhitespace(); | |||
| glyphs.add (new PositionedGlyph (font, t.getAndAdvance(), | |||
| newGlyphs.getUnchecked(i), | |||
| xOffset + thisX, yOffset, | |||
| nextX - thisX, isWhitespace)); | |||
| } | |||
| } | |||
| } | |||
| @@ -251,8 +269,8 @@ int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, | |||
| for (int i = 3; --i >= 0;) | |||
| { | |||
| glyphs.insert (endIndex++, new PositionedGlyph (xOffset, yOffset, dx, | |||
| font, '.', dotGlyphs.getFirst())); | |||
| glyphs.insert (endIndex++, new PositionedGlyph (font, '.', dotGlyphs.getFirst(), | |||
| xOffset, yOffset, dx, false)); | |||
| --numDeleted; | |||
| xOffset += dx; | |||
| @@ -35,25 +35,33 @@ | |||
| A glyph from a particular font, with a particular size, style, | |||
| typeface and position. | |||
| You should rarely need to use this class directly - for most purposes, the | |||
| GlyphArrangement class will do what you need for text layout. | |||
| @see GlyphArrangement, Font | |||
| */ | |||
| class JUCE_API PositionedGlyph | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber, | |||
| float anchorX, float baselineY, float width, bool isWhitespace); | |||
| PositionedGlyph (const PositionedGlyph& other); | |||
| PositionedGlyph& operator= (const PositionedGlyph& other); | |||
| ~PositionedGlyph(); | |||
| /** Returns the character the glyph represents. */ | |||
| juce_wchar getCharacter() const { return character; } | |||
| juce_wchar getCharacter() const noexcept { return character; } | |||
| /** Checks whether the glyph is actually empty. */ | |||
| bool isWhitespace() const { return CharacterFunctions::isWhitespace (character); } | |||
| bool isWhitespace() const noexcept { return whitespace; } | |||
| /** Returns the position of the glyph's left-hand edge. */ | |||
| float getLeft() const { return x; } | |||
| float getLeft() const noexcept { return x; } | |||
| /** Returns the position of the glyph's right-hand edge. */ | |||
| float getRight() const { return x + w; } | |||
| float getRight() const noexcept { return x + w; } | |||
| /** Returns the y position of the glyph's baseline. */ | |||
| float getBaselineY() const { return y; } | |||
| float getBaselineY() const noexcept { return y; } | |||
| /** Returns the y position of the top of the glyph. */ | |||
| float getTop() const { return y - font.getAscent(); } | |||
| /** Returns the y position of the bottom of the glyph. */ | |||
| @@ -84,12 +92,12 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| friend class GlyphArrangement; | |||
| float x, y, w; | |||
| Font font; | |||
| juce_wchar character; | |||
| int glyph; | |||
| float x, y, w; | |||
| bool whitespace; | |||
| PositionedGlyph (float x, float y, float w, const Font& font, juce_wchar character, int glyph); | |||
| JUCE_LEAK_DETECTOR (PositionedGlyph); | |||
| }; | |||
| @@ -115,7 +123,6 @@ public: | |||
| GlyphArrangement (const GlyphArrangement& other); | |||
| /** Copies another arrangement onto this one. | |||
| To add another arrangement without clearing this one, use addGlyphArrangement(). | |||
| */ | |||
| GlyphArrangement& operator= (const GlyphArrangement& other); | |||
| @@ -208,6 +215,9 @@ public: | |||
| /** Appends another glyph arrangement to this one. */ | |||
| void addGlyphArrangement (const GlyphArrangement& other); | |||
| /** Appends a custom glyph to the arrangement. */ | |||
| void addGlyph (const PositionedGlyph& glyph); | |||
| //============================================================================== | |||
| /** Draws this glyph arrangement to a graphics context. | |||
| @@ -293,9 +303,9 @@ private: | |||
| //============================================================================== | |||
| OwnedArray <PositionedGlyph> glyphs; | |||
| int insertEllipsis (const Font& font, float maxXPos, int startIndex, int endIndex); | |||
| int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, | |||
| const Justification& justification, float minimumHorizontalScale); | |||
| 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&, | |||
| const Justification&, float minimumHorizontalScale); | |||
| void spreadOutLine (int start, int numGlyphs, float targetWidth); | |||
| JUCE_LEAK_DETECTOR (GlyphArrangement); | |||
| @@ -49,7 +49,7 @@ class AffineTransform; | |||
| @see CustomTypeface, Font | |||
| */ | |||
| class JUCE_API Typeface : public ReferenceCountedObject | |||
| class JUCE_API Typeface : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| @@ -32,7 +32,7 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| class Expression::Term : public ReferenceCountedObject | |||
| class Expression::Term : public SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| Term() {} | |||
| @@ -55,7 +55,11 @@ | |||
| Once a new ReferenceCountedObject has been assigned to a pointer, be | |||
| careful not to delete the object manually. | |||
| @see ReferenceCountedObjectPtr, ReferenceCountedArray | |||
| This class uses an Atomic<int> value to hold the reference count, so that it | |||
| the pointers can be passed between threads safely. For a faster but non-thread-safe | |||
| version, use SingleThreadedReferenceCountedObject instead. | |||
| @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject | |||
| */ | |||
| class JUCE_API ReferenceCountedObject | |||
| { | |||
| @@ -84,10 +88,7 @@ public: | |||
| } | |||
| /** Returns the object's current reference count. */ | |||
| inline int getReferenceCount() const noexcept | |||
| { | |||
| return refCount.get(); | |||
| } | |||
| inline int getReferenceCount() const noexcept { return refCount.get(); } | |||
| protected: | |||
| @@ -110,6 +111,64 @@ private: | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| Adds reference-counting to an object. | |||
| This is efectively a version of the ReferenceCountedObject class, but which | |||
| uses a non-atomic counter, and so is not thread-safe (but which will be more | |||
| efficient). | |||
| For more details on how to use it, see the ReferenceCountedObject class notes. | |||
| @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray | |||
| */ | |||
| class JUCE_API SingleThreadedReferenceCountedObject | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Increments the object's reference count. | |||
| This is done automatically by the smart pointer, but is public just | |||
| in case it's needed for nefarious purposes. | |||
| */ | |||
| inline void incReferenceCount() noexcept | |||
| { | |||
| ++refCount; | |||
| } | |||
| /** Decreases the object's reference count. | |||
| If the count gets to zero, the object will be deleted. | |||
| */ | |||
| inline void decReferenceCount() noexcept | |||
| { | |||
| jassert (getReferenceCount() > 0); | |||
| if (--refCount == 0) | |||
| delete this; | |||
| } | |||
| /** Returns the object's current reference count. */ | |||
| inline int getReferenceCount() const noexcept { return refCount; } | |||
| protected: | |||
| //============================================================================== | |||
| /** Creates the reference-counted object (with an initial ref count of zero). */ | |||
| SingleThreadedReferenceCountedObject() : refCount (0) {} | |||
| /** Destructor. */ | |||
| virtual ~SingleThreadedReferenceCountedObject() | |||
| { | |||
| // it's dangerous to delete an object that's still referenced by something else! | |||
| jassert (getReferenceCount() == 0); | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| int refCount; | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| @@ -81,7 +81,7 @@ | |||
| @see WeakReference::Master | |||
| */ | |||
| template <class ObjectType> | |||
| template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject> | |||
| class WeakReference | |||
| { | |||
| public: | |||
| @@ -129,7 +129,7 @@ public: | |||
| in your code! | |||
| @see WeakReference | |||
| */ | |||
| class SharedPointer : public ReferenceCountedObject | |||
| class SharedPointer : public ReferenceCountingType | |||
| { | |||
| public: | |||
| explicit SharedPointer (ObjectType* const owner_) noexcept : owner (owner_) {} | |||