- 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:
@@ -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.
|
||||
|
||||
|
||||
+1
-1
@@ -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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user