From 1dac02369ec71041f65e1ba4dc09aa52cfc1914f Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Wed, 1 Jun 2011 11:11:39 +0100 Subject: [PATCH] New method Array::resize(). Tweaked AudioThumbnail to avoid clearing the input source when loaded. New class SingleThreadedReferenceCountedObject (and used this for Font, Typeface, Expression, Value and ValueTree classes, since none of these were safe to use with threads anyway). Minor additions to GlyphArrangement. --- juce_amalgamated.cpp | 76 ++++++---- juce_amalgamated.h | 141 ++++++++++++++---- .../juce_AudioThumbnail.cpp | 6 +- .../audio_file_formats/juce_AudioThumbnail.h | 1 + src/containers/juce_Array.h | 18 +++ src/containers/juce_Value.h | 2 +- src/containers/juce_ValueTree.h | 11 +- src/gui/components/menus/juce_PopupMenu.h | 2 +- .../juce_LowLevelGraphicsSoftwareRenderer.cpp | 2 +- src/gui/graphics/fonts/juce_Font.h | 2 +- .../graphics/fonts/juce_GlyphArrangement.cpp | 66 +++++--- .../graphics/fonts/juce_GlyphArrangement.h | 32 ++-- src/gui/graphics/fonts/juce_Typeface.h | 2 +- src/maths/juce_Expression.cpp | 2 +- src/memory/juce_ReferenceCountedObject.h | 69 ++++++++- src/memory/juce_WeakReference.h | 4 +- 16 files changed, 324 insertions(+), 112 deletions(-) diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index e80d7a47b7..88afcb242f 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -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 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; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 04b3a3b992..287d3dab45 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -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 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 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 +template 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 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); diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp index b6dc660ab7..be1bd9f36b 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp @@ -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); diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.h b/src/audio/audio_file_formats/juce_AudioThumbnail.h index f9f84ccd22..99c70f899c 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.h +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.h @@ -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); diff --git a/src/containers/juce_Array.h b/src/containers/juce_Array.h index 195638972b..e20e0e76a3 100644 --- a/src/containers/juce_Array.h +++ b/src/containers/juce_Array.h @@ -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 diff --git a/src/containers/juce_Value.h b/src/containers/juce_Value.h index b06f37bc54..232d69899a 100644 --- a/src/containers/juce_Value.h +++ b/src/containers/juce_Value.h @@ -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: diff --git a/src/containers/juce_ValueTree.h b/src/containers/juce_ValueTree.h index 3ba66cc677..017133c5b2 100644 --- a/src/containers/juce_ValueTree.h +++ b/src/containers/juce_ValueTree.h @@ -466,14 +466,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); diff --git a/src/gui/components/menus/juce_PopupMenu.h b/src/gui/components/menus/juce_PopupMenu.h index 550557fa1d..e7c4b40d46 100644 --- a/src/gui/components/menus/juce_PopupMenu.h +++ b/src/gui/components/menus/juce_PopupMenu.h @@ -415,7 +415,7 @@ public: @see PopupMenu::addCustomItem */ class JUCE_API CustomComponent : public Component, - public ReferenceCountedObject + public SingleThreadedReferenceCountedObject { public: /** Creates a custom item. diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index 93bc506bb1..c33adea508 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -1018,7 +1018,7 @@ private: }; //============================================================================== -class ClipRegionBase : public ReferenceCountedObject +class ClipRegionBase : public SingleThreadedReferenceCountedObject { public: ClipRegionBase() {} diff --git a/src/gui/graphics/fonts/juce_Font.h b/src/gui/graphics/fonts/juce_Font.h index 07d01f2fa0..6604b65d94 100644 --- a/src/gui/graphics/fonts/juce_Font.h +++ b/src/gui/graphics/fonts/juce_Font.h @@ -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; diff --git a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp index 2b4171bfc1..077c8882d1 100644 --- a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp +++ b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp @@ -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 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; diff --git a/src/gui/graphics/fonts/juce_GlyphArrangement.h b/src/gui/graphics/fonts/juce_GlyphArrangement.h index d72b353030..197e68a04e 100644 --- a/src/gui/graphics/fonts/juce_GlyphArrangement.h +++ b/src/gui/graphics/fonts/juce_GlyphArrangement.h @@ -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 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); diff --git a/src/gui/graphics/fonts/juce_Typeface.h b/src/gui/graphics/fonts/juce_Typeface.h index 489cbc98f6..eab11448cb 100644 --- a/src/gui/graphics/fonts/juce_Typeface.h +++ b/src/gui/graphics/fonts/juce_Typeface.h @@ -49,7 +49,7 @@ class AffineTransform; @see CustomTypeface, Font */ -class JUCE_API Typeface : public ReferenceCountedObject +class JUCE_API Typeface : public SingleThreadedReferenceCountedObject { public: //============================================================================== diff --git a/src/maths/juce_Expression.cpp b/src/maths/juce_Expression.cpp index 7d6c7cd38e..cb0e2c7d53 100644 --- a/src/maths/juce_Expression.cpp +++ b/src/maths/juce_Expression.cpp @@ -32,7 +32,7 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -class Expression::Term : public ReferenceCountedObject +class Expression::Term : public SingleThreadedReferenceCountedObject { public: Term() {} diff --git a/src/memory/juce_ReferenceCountedObject.h b/src/memory/juce_ReferenceCountedObject.h index 1a3a6f09bf..e4f2f03e9f 100644 --- a/src/memory/juce_ReferenceCountedObject.h +++ b/src/memory/juce_ReferenceCountedObject.h @@ -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 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; +}; + //============================================================================== /** diff --git a/src/memory/juce_WeakReference.h b/src/memory/juce_WeakReference.h index 74751b4f2c..afed7b0746 100644 --- a/src/memory/juce_WeakReference.h +++ b/src/memory/juce_WeakReference.h @@ -81,7 +81,7 @@ @see WeakReference::Master */ -template +template 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_) {}