- Library code update

- project update (added Eigen)

git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-12-20 20:59:48 +00:00
parent 1b4d8e9f54
commit dc5560392f
312 changed files with 6349 additions and 4195 deletions
@@ -438,14 +438,14 @@ void Graphics::drawRect (Rectangle<float> r, const float lineThickness) const
//==============================================================================
void Graphics::fillEllipse (const Rectangle<float>& area) const
{
fillEllipse (area.getX(), area.getY(), area.getWidth(), area.getHeight());
Path p;
p.addEllipse (area);
fillPath (p);
}
void Graphics::fillEllipse (float x, float y, float width, float height) const
void Graphics::fillEllipse (float x, float y, float w, float h) const
{
Path p;
p.addEllipse (x, y, width, height);
fillPath (p);
fillEllipse (Rectangle<float> (x, y, w, h));
}
void Graphics::drawEllipse (float x, float y, float width, float height, float lineThickness) const
@@ -158,7 +158,7 @@ public:
void drawText (const String& text,
int x, int y, int width, int height,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Draws a line of text within a specified rectangle.
@@ -172,7 +172,7 @@ public:
void drawText (const String& text,
const Rectangle<int>& area,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Draws a line of text within a specified rectangle.
@@ -186,7 +186,7 @@ public:
void drawText (const String& text,
const Rectangle<float>& area,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Tries to draw a text string inside a given space.
@@ -384,7 +384,7 @@ void LowLevelGraphicsPostScriptRenderer::fillPath (const Path& path, const Affin
{
// this doesn't work correctly yet - it could be improved to handle solid gradients, but
// postscript can't do semi-transparent ones.
notPossibleInPostscriptAssert // you can disable this warning by setting the WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS flag at the top of this file
notPossibleInPostscriptAssert; // you can disable this warning by setting the WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS flag at the top of this file
writeClip();
out << "gsave ";
@@ -52,6 +52,11 @@ public:
/** Loads a typeface from a previously saved stream.
The stream must have been created by writeToStream().
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietary format.
@see writeToStream
*/
explicit CustomTypeface (InputStream& serialisedTypefaceStream);
@@ -116,7 +121,7 @@ public:
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietory format.
is more appropriate than using this class to store it in a proprietary format.
*/
bool writeToStream (OutputStream& outputStream);
@@ -278,13 +278,13 @@ Font& Font::operator= (const Font& other) noexcept
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
Font::Font (Font&& other) noexcept
: font (static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font))
: font (static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font))
{
}
Font& Font::operator= (Font&& other) noexcept
{
font = static_cast <ReferenceCountedObjectPtr <SharedFontInternal>&&> (other.font);
font = static_cast<ReferenceCountedObjectPtr<SharedFontInternal>&&> (other.font);
return *this;
}
#endif
@@ -640,7 +640,7 @@ float Font::getStringWidthFloat (const String& text) const
return w * font->height * font->horizontalScale;
}
void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const
void Font::getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) const
{
getTypeface()->getGlyphPositions (text, glyphs, xOffsets);
@@ -169,7 +169,7 @@ public:
*/
static const String& getDefaultSansSerifFontName();
/** Returns a typeface font family that represents the default sans-serif font.
/** Returns a typeface font family that represents the default serif font.
Note that this method just returns a generic placeholder string that means "the default
serif font" - it's not the actual font family of this font.
@@ -178,7 +178,7 @@ public:
*/
static const String& getDefaultSerifFontName();
/** Returns a typeface font family that represents the default sans-serif font.
/** Returns a typeface font family that represents the default monospaced font.
Note that this method just returns a generic placeholder string that means "the default
monospaced font" - it's not the actual font family of this font.
@@ -187,10 +187,10 @@ public:
*/
static const String& getDefaultMonospacedFontName();
/** Returns a typeface font style that represents the default sans-serif font.
/** Returns a font style name that represents the default style.
Note that this method just returns a generic placeholder string that means "the default
font style" - it's not the actual font style of this font.
font style" - it's not the actual name of the font style of any particular font.
@see setTypefaceStyle
*/
@@ -449,7 +449,7 @@ public:
private:
//==============================================================================
class SharedFontInternal;
ReferenceCountedObjectPtr <SharedFontInternal> font;
ReferenceCountedObjectPtr<SharedFontInternal> font;
void dupeInternalIfShared();
void checkTypefaceSuitability();
float getHeightToPointsFactor() const;
@@ -40,6 +40,27 @@ PositionedGlyph::PositionedGlyph (const PositionedGlyph& other)
{
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
PositionedGlyph::PositionedGlyph (PositionedGlyph&& other) noexcept
: font (static_cast<Font&&> (other.font)),
character (other.character), glyph (other.glyph),
x (other.x), y (other.y), w (other.w), whitespace (other.whitespace)
{
}
PositionedGlyph& PositionedGlyph::operator= (PositionedGlyph&& other) noexcept
{
font = static_cast<Font&&> (other.font);
character = other.character;
glyph = other.glyph;
x = other.x;
y = other.y;
w = other.w;
whitespace = other.whitespace;
return *this;
}
#endif
PositionedGlyph::~PositionedGlyph() {}
PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other)
@@ -182,8 +203,8 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
{
if (text.isNotEmpty())
{
Array <int> newGlyphs;
Array <float> xOffsets;
Array<int> newGlyphs;
Array<float> xOffsets;
font.getGlyphPositions (text, newGlyphs, xOffsets);
const int textLen = newGlyphs.size();
glyphs.ensureStorageAllocated (glyphs.size() + textLen);
@@ -353,174 +374,40 @@ void GlyphArrangement::addFittedText (const Font& f,
if (text.containsAnyOf ("\r\n"))
{
GlyphArrangement ga;
ga.addJustifiedText (f, text, x, y, width, layout);
const Rectangle<float> bb (ga.getBoundingBox (0, -1, false));
float dy = y - bb.getY();
if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f;
else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight());
ga.moveRangeOfGlyphs (0, -1, 0.0f, dy);
glyphs.addArray (ga.glyphs);
return;
addLinesWithLineBreaks (text, f, x, y, width, height, layout);
}
int startIndex = glyphs.size();
addLineOfText (f, text.trim(), x, y);
if (glyphs.size() > startIndex)
else
{
float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
- glyphs.getReference (startIndex).getLeft();
const int startIndex = glyphs.size();
const String trimmed (text.trim());
addLineOfText (f, trimmed, x, y);
const int numGlyphs = glyphs.size() - startIndex;
if (lineWidth <= 0)
return;
if (lineWidth * minimumHorizontalScale < width)
if (numGlyphs > 0)
{
if (lineWidth > width)
stretchRangeOfGlyphs (startIndex, glyphs.size() - startIndex,
width / lineWidth);
const float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
- glyphs.getReference (startIndex).getLeft();
justifyGlyphs (startIndex, glyphs.size() - startIndex,
x, y, width, height, layout);
}
else if (maximumLines <= 1)
{
fitLineIntoSpace (startIndex, glyphs.size() - startIndex,
x, y, width, height, f, layout, minimumHorizontalScale);
}
else
{
Font font (f);
String txt (text.trim());
const int length = txt.length();
const int originalStartIndex = startIndex;
int numLines = 1;
if (length <= 12 && ! txt.containsAnyOf (" -\t\r\n"))
maximumLines = 1;
maximumLines = jmin (maximumLines, length);
while (numLines < maximumLines)
if (lineWidth > 0)
{
++numLines;
const float newFontHeight = height / (float) numLines;
if (newFontHeight < font.getHeight())
if (lineWidth * minimumHorizontalScale < width)
{
font.setHeight (jmax (8.0f, newFontHeight));
if (lineWidth > width)
stretchRangeOfGlyphs (startIndex, numGlyphs, width / lineWidth);
removeRangeOfGlyphs (startIndex, -1);
addLineOfText (font, txt, x, y);
lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
- glyphs.getReference (startIndex).getLeft();
justifyGlyphs (startIndex, numGlyphs, x, y, width, height, layout);
}
if (numLines > lineWidth / width || newFontHeight < 8.0f)
break;
}
if (numLines < 1)
numLines = 1;
float lineY = y;
float widthPerLine = lineWidth / numLines;
for (int line = 0; line < numLines; ++line)
{
int i = startIndex;
float lineStartX = glyphs.getReference (startIndex).getLeft();
if (line == numLines - 1)
else if (maximumLines <= 1)
{
widthPerLine = width;
i = glyphs.size();
fitLineIntoSpace (startIndex, numGlyphs, x, y, width, height,
f, layout, minimumHorizontalScale);
}
else
{
while (i < glyphs.size())
{
lineWidth = (glyphs.getReference (i).getRight() - lineStartX);
if (lineWidth > widthPerLine)
{
// got to a point where the line's too long, so skip forward to find a
// good place to break it..
const int searchStartIndex = i;
while (i < glyphs.size())
{
if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width)
{
if (glyphs.getReference (i).isWhitespace()
|| glyphs.getReference (i).getCharacter() == '-')
{
++i;
break;
}
}
else
{
// can't find a suitable break, so try looking backwards..
i = searchStartIndex;
for (int back = 1; back < jmin (7, i - startIndex - 1); ++back)
{
if (glyphs.getReference (i - back).isWhitespace()
|| glyphs.getReference (i - back).getCharacter() == '-')
{
i -= back - 1;
break;
}
}
break;
}
++i;
}
break;
}
++i;
}
int wsStart = i;
while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace())
--wsStart;
int wsEnd = i;
while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace())
++wsEnd;
removeRangeOfGlyphs (wsStart, wsEnd - wsStart);
i = jmax (wsStart, startIndex + 1);
splitLines (trimmed, f, startIndex, x, y, width, height,
maximumLines, lineWidth, layout, minimumHorizontalScale);
}
i -= fitLineIntoSpace (startIndex, i - startIndex,
x, lineY, width, font.getHeight(), font,
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred,
minimumHorizontalScale);
startIndex = i;
lineY += font.getHeight();
if (startIndex >= glyphs.size())
break;
}
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex,
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified);
}
}
}
@@ -540,6 +427,24 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float d
}
}
void GlyphArrangement::addLinesWithLineBreaks (const String& text, const Font& f,
float x, float y, float width, float height, Justification layout)
{
GlyphArrangement ga;
ga.addJustifiedText (f, text, x, y, width, layout);
const Rectangle<float> bb (ga.getBoundingBox (0, -1, false));
float dy = y - bb.getY();
if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f;
else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight());
ga.moveRangeOfGlyphs (0, -1, 0.0f, dy);
glyphs.addArray (ga.glyphs);
}
int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font,
Justification justification, float minimumHorizontalScale)
{
@@ -702,9 +607,142 @@ void GlyphArrangement::spreadOutLine (const int start, const int num, const floa
}
}
void GlyphArrangement::splitLines (const String& text, Font font, int startIndex,
float x, float y, float width, float height, int maximumLines,
float lineWidth, Justification layout, float minimumHorizontalScale)
{
const int length = text.length();
const int originalStartIndex = startIndex;
int numLines = 1;
if (length <= 12 && ! text.containsAnyOf (" -\t\r\n"))
maximumLines = 1;
maximumLines = jmin (maximumLines, length);
while (numLines < maximumLines)
{
++numLines;
const float newFontHeight = height / (float) numLines;
if (newFontHeight < font.getHeight())
{
font.setHeight (jmax (8.0f, newFontHeight));
removeRangeOfGlyphs (startIndex, -1);
addLineOfText (font, text, x, y);
lineWidth = glyphs.getReference (glyphs.size() - 1).getRight()
- glyphs.getReference (startIndex).getLeft();
}
// Try to estimate the point at which there are enough lines to fit the text,
// allowing for unevenness in the lengths due to differently sized words.
const float lineLengthUnevennessAllowance = 80.0f;
if (numLines > (lineWidth + lineLengthUnevennessAllowance) / width || newFontHeight < 8.0f)
break;
}
if (numLines < 1)
numLines = 1;
float lineY = y;
float widthPerLine = lineWidth / numLines;
for (int line = 0; line < numLines; ++line)
{
int i = startIndex;
float lineStartX = glyphs.getReference (startIndex).getLeft();
if (line == numLines - 1)
{
widthPerLine = width;
i = glyphs.size();
}
else
{
while (i < glyphs.size())
{
lineWidth = (glyphs.getReference (i).getRight() - lineStartX);
if (lineWidth > widthPerLine)
{
// got to a point where the line's too long, so skip forward to find a
// good place to break it..
const int searchStartIndex = i;
while (i < glyphs.size())
{
if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width)
{
if (glyphs.getReference (i).isWhitespace()
|| glyphs.getReference (i).getCharacter() == '-')
{
++i;
break;
}
}
else
{
// can't find a suitable break, so try looking backwards..
i = searchStartIndex;
for (int back = 1; back < jmin (7, i - startIndex - 1); ++back)
{
if (glyphs.getReference (i - back).isWhitespace()
|| glyphs.getReference (i - back).getCharacter() == '-')
{
i -= back - 1;
break;
}
}
break;
}
++i;
}
break;
}
++i;
}
int wsStart = i;
while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace())
--wsStart;
int wsEnd = i;
while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace())
++wsEnd;
removeRangeOfGlyphs (wsStart, wsEnd - wsStart);
i = jmax (wsStart, startIndex + 1);
}
i -= fitLineIntoSpace (startIndex, i - startIndex,
x, lineY, width, font.getHeight(), font,
layout.getOnlyHorizontalFlags() | Justification::verticallyCentred,
minimumHorizontalScale);
startIndex = i;
lineY += font.getHeight();
if (startIndex >= glyphs.size())
break;
}
justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex,
x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified);
}
//==============================================================================
inline void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGlyph& pg,
const int i, const AffineTransform& transform) const
void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGlyph& pg,
const int i, const AffineTransform& transform) const
{
const float lineThickness = (pg.font.getDescent()) * 0.3f;
@@ -46,6 +46,12 @@ public:
PositionedGlyph (const PositionedGlyph&);
PositionedGlyph& operator= (const PositionedGlyph&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
PositionedGlyph (PositionedGlyph&&) noexcept;
PositionedGlyph& operator= (PositionedGlyph&&) noexcept;
#endif
~PositionedGlyph();
/** Returns the character the glyph represents. */
@@ -295,12 +301,15 @@ public:
private:
//==============================================================================
Array <PositionedGlyph> glyphs;
Array<PositionedGlyph> glyphs;
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&,
Justification, float minimumHorizontalScale);
void spreadOutLine (int start, int numGlyphs, float targetWidth);
void splitLines (const String&, Font, int start, float x, float y, float w, float h, int maxLines,
float lineWidth, Justification, float minimumHorizontalScale);
void addLinesWithLineBreaks (const String&, const Font&, float x, float y, float width, float height, Justification);
void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, const AffineTransform&) const;
JUCE_LEAK_DETECTOR (GlyphArrangement)
@@ -83,8 +83,8 @@ public:
void transformPoint (ValueType& x, ValueType& y) const noexcept
{
const ValueType oldX = x;
x = static_cast <ValueType> (mat00 * oldX + mat01 * y + mat02);
y = static_cast <ValueType> (mat10 * oldX + mat11 * y + mat12);
x = static_cast<ValueType> (mat00 * oldX + mat01 * y + mat02);
y = static_cast<ValueType> (mat10 * oldX + mat11 * y + mat12);
}
/** Transforms two 2D coordinates using this matrix.
@@ -97,10 +97,10 @@ public:
ValueType& x2, ValueType& y2) const noexcept
{
const ValueType oldX1 = x1, oldX2 = x2;
x1 = static_cast <ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
y1 = static_cast <ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
x2 = static_cast <ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
y2 = static_cast <ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
}
/** Transforms three 2D coordinates using this matrix.
@@ -114,12 +114,12 @@ public:
ValueType& x3, ValueType& y3) const noexcept
{
const ValueType oldX1 = x1, oldX2 = x2, oldX3 = x3;
x1 = static_cast <ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
y1 = static_cast <ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
x2 = static_cast <ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
y2 = static_cast <ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
x3 = static_cast <ValueType> (mat00 * oldX3 + mat01 * y3 + mat02);
y3 = static_cast <ValueType> (mat10 * oldX3 + mat11 * y3 + mat12);
x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
x3 = static_cast<ValueType> (mat00 * oldX3 + mat01 * y3 + mat02);
y3 = static_cast<ValueType> (mat10 * oldX3 + mat11 * y3 + mat12);
}
//==============================================================================
@@ -231,8 +231,7 @@ public:
float x10, float y10,
float x01, float y01) noexcept;
/** Returns the transform that will map three specified points onto three target points.
*/
/** Returns the transform that will map three specified points onto three target points. */
static AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1,
float sourceX2, float sourceY2, float targetX2, float targetY2,
float sourceX3, float sourceY3, float targetX3, float targetY3) noexcept;
@@ -436,9 +436,7 @@ void Path::addRectangle (const float x, const float y,
data.elements [numElements++] = closeSubPathMarker;
}
void Path::addRoundedRectangle (const float x, const float y,
const float w, const float h,
float csx, float csy)
void Path::addRoundedRectangle (float x, float y, float w, float h, float csx, float csy)
{
addRoundedRectangle (x, y, w, h, csx, csy, true, true, true, true);
}
@@ -498,9 +496,7 @@ void Path::addRoundedRectangle (const float x, const float y, const float w, con
closeSubPath();
}
void Path::addRoundedRectangle (const float x, const float y,
const float w, const float h,
float cs)
void Path::addRoundedRectangle (float x, float y, float w, float h, float cs)
{
addRoundedRectangle (x, y, w, h, cs, cs);
}
@@ -527,15 +523,19 @@ void Path::addQuadrilateral (const float x1, const float y1,
closeSubPath();
}
void Path::addEllipse (const float x, const float y,
const float w, const float h)
void Path::addEllipse (float x, float y, float w, float h)
{
const float hw = w * 0.5f;
addEllipse (Rectangle<float> (x, y, w, h));
}
void Path::addEllipse (Rectangle<float> area)
{
const float hw = area.getWidth() * 0.5f;
const float hw55 = hw * 0.55f;
const float hh = h * 0.5f;
const float hh = area.getHeight() * 0.5f;
const float hh55 = hh * 0.55f;
const float cx = x + hw;
const float cy = y + hh;
const float cx = area.getX() + hw;
const float cy = area.getY() + hh;
startNewSubPath (cx, cy - hh);
cubicTo (cx + hw55, cy - hh, cx + hw, cy - hh55, cx + hw, cy);
@@ -391,13 +391,17 @@ public:
float x4, float y4);
/** Adds an ellipse to the path.
The shape is added as a new sub-path. (Any currently open paths will be left open).
@see addArc
*/
void addEllipse (float x, float y, float width, float height);
/** Adds an ellipse to the path.
The shape is added as a new sub-path. (Any currently open paths will be left open).
@see addArc
*/
void addEllipse (Rectangle<float> area);
/** Adds an elliptical arc to the current path.
Note that when specifying the start and end angles, the curve will be drawn either clockwise
@@ -213,6 +213,9 @@ public:
/** Casts this point to a Point<double> object. */
Point<double> toDouble() const noexcept { return Point<double> (static_cast<double> (x), static_cast<double> (y)); }
/** Casts this point to a Point<int> object using roundToInt() to convert the values. */
Point<int> roundToInt() const noexcept { return Point<int> (juce::roundToInt (x), juce::roundToInt (y)); }
/** Returns the point as a string in the form "x, y". */
String toString() const { return String (x) + ", " + String (y); }
@@ -628,6 +628,17 @@ public:
/** Standard method for iterating the rectangles in the list. */
const RectangleType* end() const noexcept { return rects.end(); }
/** Increases the internal storage to hold a minimum number of rectangles.
Calling this before adding a large number of rectangles means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
@see Array::ensureStorageAllocated
*/
void ensureStorageAllocated (int minNumRectangles)
{
rects.ensureStorageAllocated (minNumRectangles);
}
private:
//==============================================================================
Array<RectangleType> rects;
@@ -488,12 +488,13 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
HeapBlock <uint8> rowData ((size_t) width * 4);
HeapBlock<uint8> rowData ((size_t) width * 4);
png_color_8 sig_bit;
sig_bit.red = 8;
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.blue = 8;
sig_bit.gray = 0;
sig_bit.alpha = 8;
png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit);
@@ -1026,7 +1026,7 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr,
if ((transforms & PNG_TRANSFORM_SHIFT)
&& png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
{
png_color_8p sig_bit;
png_color_8p sig_bit = 0;
png_get_sBIT(png_ptr, info_ptr, &sig_bit);
png_set_shift(png_ptr, sig_bit);
@@ -197,11 +197,11 @@ Image Image::getClippedImage (const Rectangle<int>& area) const
//==============================================================================
Image::Image()
Image::Image() noexcept
{
}
Image::Image (ImagePixelData* const instance)
Image::Image (ImagePixelData* const instance) noexcept
: image (instance)
{
}
@@ -216,7 +216,7 @@ Image::Image (const PixelFormat format, int width, int height, bool clearImage,
{
}
Image::Image (const Image& other)
Image::Image (const Image& other) noexcept
: image (other.image)
{
}
@@ -67,7 +67,7 @@ public:
//==============================================================================
/** Creates a null image. */
Image();
Image() noexcept;
/** Creates an image with a specified size and format.
@@ -106,7 +106,7 @@ public:
point to the same shared image data. To make sure that an Image object has its own unique,
unshared internal data, call duplicateIfShared().
*/
Image (const Image&);
Image (const Image&) noexcept;
/** Makes this image refer to the same underlying image as another object.
@@ -408,7 +408,7 @@ public:
ImagePixelData* getPixelData() const noexcept { return image; }
/** @internal */
explicit Image (ImagePixelData*);
explicit Image (ImagePixelData*) noexcept;
private:
//==============================================================================
@@ -1,7 +1,7 @@
{
"id": "juce_graphics",
"name": "JUCE graphics classes",
"version": "3.0.5",
"version": "3.0.8",
"description": "Classes for 2D vector graphics, image loading/saving, font handling, etc.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",
@@ -589,6 +589,10 @@ namespace EdgeTableFillers
filler[2].set (sourceColour);
filler[3].set (sourceColour);
}
else
{
areRGBComponentsEqual = false;
}
}
forcedinline void setEdgeTableYPos (const int y) noexcept
@@ -29,7 +29,7 @@ class CoreGraphicsImage : public ImagePixelData
{
public:
CoreGraphicsImage (const Image::PixelFormat format, const int w, const int h, const bool clearImage)
: ImagePixelData (format, w, h)
: ImagePixelData (format, w, h), cachedImageRef (0)
{
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);
lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
@@ -47,11 +47,13 @@ public:
~CoreGraphicsImage()
{
freeCachedImageRef();
CGContextRelease (context);
}
LowLevelGraphicsContext* createLowLevelContext() override
{
freeCachedImageRef();
sendDataChangeMessage();
return new CoreGraphicsContext (context, height, 1.0f);
}
@@ -64,7 +66,10 @@ public:
bitmap.pixelStride = pixelStride;
if (mode != Image::BitmapData::readOnly)
{
freeCachedImageRef();
sendDataChangeMessage();
}
}
ImagePixelData* clone() override
@@ -77,6 +82,27 @@ public:
ImageType* createType() const override { return new NativeImageType(); }
//==============================================================================
static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)
{
CoreGraphicsImage* const cgim = dynamic_cast<CoreGraphicsImage*> (juceImage.getPixelData());
if (cgim != nullptr && cgim->cachedImageRef != 0)
{
CGImageRetain (cgim->cachedImageRef);
return cgim->cachedImageRef;
}
CGImageRef ref = createImage (juceImage, colourSpace, false);
if (cgim != nullptr)
{
CGImageRetain (ref);
cgim->cachedImageRef = ref;
}
return ref;
}
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, const bool mustOutliveSource)
{
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
@@ -106,10 +132,20 @@ public:
//==============================================================================
CGContextRef context;
CGImageRef cachedImageRef;
HeapBlock<uint8> imageData;
int pixelStride, lineStride;
private:
void freeCachedImageRef()
{
if (cachedImageRef != 0)
{
CGImageRelease (cachedImageRef);
cachedImageRef = 0;
}
}
static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format)
{
#if JUCE_BIG_ENDIAN
@@ -454,7 +490,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
{
const int iw = sourceImage.getWidth();
const int ih = sourceImage.getHeight();
CGImageRef image = CoreGraphicsImage::createImage (sourceImage, rgbColourSpace, false);
CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, rgbColourSpace);
CGContextSaveGState (context);
CGContextSetAlpha (context, state->fillType.getOpacity());
@@ -1280,15 +1280,25 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
}
#if JUCE_CORETEXT_AVAILABLE
static bool containsNoMemoryTypefaces (const AttributedString& text)
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text)
{
const int numCharacterAttributes = text.getNumAttributes();
for (int i = 0; i < numCharacterAttributes; ++i)
{
if (const Font* const f = text.getAttribute (i)->getFont())
{
if (OSXTypeface* tf = dynamic_cast<OSXTypeface*> (f->getTypeface()))
{
if (tf->isMemoryFont)
return false;
}
else if (dynamic_cast<CustomTypeface*> (f->getTypeface()) != nullptr)
{
return false;
}
}
}
return true;
}
@@ -1299,7 +1309,7 @@ bool TextLayout::createNativeLayout (const AttributedString& text)
#if JUCE_CORETEXT_AVAILABLE
// Seems to be an unfathomable bug in CoreText which prevents the layout working with
// typefaces that were loaded from memory, so have to fallback if we hit any of those..
if (containsNoMemoryTypefaces (text))
if (canAllTypefacesBeUsedInLayout (text))
{
CoreTextTypeLayout::createLayout (*this, text);
return true;
@@ -29,8 +29,9 @@ namespace DirectWriteTypeLayout
class CustomDirectWriteTextRenderer : public ComBaseClassHelper<IDWriteTextRenderer>
{
public:
CustomDirectWriteTextRenderer (IDWriteFontCollection* const fonts)
CustomDirectWriteTextRenderer (IDWriteFontCollection* const fonts, const AttributedString& as)
: ComBaseClassHelper<IDWriteTextRenderer> (0),
attributedString (as),
fontCollection (fonts),
currentLine (-1),
lastOriginY (-10000.0f)
@@ -89,20 +90,16 @@ namespace DirectWriteTypeLayout
glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, glyphRun));
glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun));
String fontFamily, fontStyle;
getFontFamilyAndStyle (glyphRun, fontFamily, fontStyle);
TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition,
runDescription->textPosition + runDescription->stringLength),
glyphRun->glyphCount);
glyphLine.runs.add (glyphRunLayout);
glyphRun->fontFace->GetMetrics (&dwFontMetrics);
const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;
glyphRunLayout->font = Font (fontFamily, fontStyle, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
glyphRunLayout->font = getFontForRun (glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect));
const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin);
@@ -127,6 +124,7 @@ namespace DirectWriteTypeLayout
}
private:
const AttributedString& attributedString;
IDWriteFontCollection* const fontCollection;
int currentLine;
float lastOriginY;
@@ -145,19 +143,22 @@ namespace DirectWriteTypeLayout
return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a);
}
void getFontFamilyAndStyle (DWRITE_GLYPH_RUN const* glyphRun, String& family, String& style) const
Font getFontForRun (DWRITE_GLYPH_RUN const* glyphRun, float fontHeight)
{
for (int i = 0; i < attributedString.getNumAttributes(); ++i)
if (const Font* font = attributedString.getAttribute(i)->getFont())
if (WindowsDirectWriteTypeface* wt = dynamic_cast<WindowsDirectWriteTypeface*> (font->getTypeface()))
if (wt->getIDWriteFontFace() == glyphRun->fontFace)
return font->withHeight (fontHeight);
ComSmartPtr<IDWriteFont> dwFont;
HRESULT hr = fontCollection->GetFontFromFontFace (glyphRun->fontFace, dwFont.resetAndGetPointerAddress());
jassert (dwFont != nullptr);
{
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress());
family = getFontFamilyName (dwFontFamily);
}
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress());
style = getFontFaceName (dwFont);
return Font (getFontFamilyName (dwFontFamily), getFontFaceName (dwFont), fontHeight);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomDirectWriteTextRenderer)
@@ -352,11 +353,11 @@ namespace DirectWriteTypeLayout
layout.ensureStorageAllocated (actualLineCount);
{
ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection));
ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text));
hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0);
}
HeapBlock <DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount);
HeapBlock<DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount);
hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount);
int lastLocation = 0;
const int numLines = jmin ((int) actualLineCount, layout.getNumLines());
@@ -384,11 +385,27 @@ namespace DirectWriteTypeLayout
}
}
}
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text)
{
const int numCharacterAttributes = text.getNumAttributes();
for (int i = 0; i < numCharacterAttributes; ++i)
if (const Font* const font = text.getAttribute (i)->getFont())
if (dynamic_cast<WindowsDirectWriteTypeface*> (font->getTypeface()) == nullptr)
return false;
return true;
}
#endif
bool TextLayout::createNativeLayout (const AttributedString& text)
{
#if JUCE_USE_DIRECTWRITE
if (! canAllTypefacesBeUsedInLayout (text))
return false;
SharedResourcePointer<Direct2DFactories> factories;
if (factories->d2dFactory != nullptr && factories->systemFonts != nullptr)
@@ -139,27 +139,27 @@ public:
hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());
// Get a specific font in the font family using typeface style
ComSmartPtr<IDWriteFont> dwFont;
uint32 fontFacesCount = 0;
fontFacesCount = dwFontFamily->GetFontCount();
for (int i = fontFacesCount; --i >= 0;)
{
hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());
ComSmartPtr<IDWriteFont> dwFont;
if (i == 0)
break;
for (int i = (int) dwFontFamily->GetFontCount(); --i >= 0;)
{
hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress());
if (i == 0)
break;
if (font.getTypefaceStyle() == getLocalisedName (faceNames))
break;
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress());
if (font.getTypefaceStyle() == getLocalisedName (faceNames))
break;
}
jassert (dwFont != nullptr);
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress());
}
jassert (dwFont != nullptr);
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress());
if (dwFontFace != nullptr)
{
DWRITE_FONT_METRICS dwFontMetrics;
@@ -506,8 +506,8 @@ private:
lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
lf.lfQuality = PROOF_QUALITY;
lf.lfItalic = (BYTE) (style == "Italic" ? TRUE : FALSE);
lf.lfWeight = style == "Bold" ? FW_BOLD : FW_NORMAL;
lf.lfItalic = (BYTE) (style.contains ("Italic") ? TRUE : FALSE);
lf.lfWeight = style.contains ("Bold") ? FW_BOLD : FW_NORMAL;
lf.lfHeight = -256;
name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));