1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-11 23:54:18 +00:00

Improvements to path rendering and fix for PathStrokeType generating incorrect paths for some shapes. Added OSX10.4 compatibility for new new typeface classes.

This commit is contained in:
Julian Storer 2009-11-10 17:45:06 +00:00
parent dc83bf01e1
commit ca727ec2bb
12 changed files with 795 additions and 355 deletions

View file

@ -146,7 +146,7 @@ public:
true); // resize the components' heights as well as widths
// now lay out the text box and the controls below it..
int x = verticalLayout.getItemCurrentPosition (2);
int x = verticalLayout.getItemCurrentPosition (2) + 4;
textBox->setBounds (x, 0, getWidth() - x, getHeight() - 110);
x += 70;
sizeSlider->setBounds (x, getHeight() - 106, getWidth() - x, 22);

View file

@ -78825,13 +78825,121 @@ BEGIN_JUCE_NAMESPACE
const int juce_edgeTableDefaultEdgesPerLine = 32;
EdgeTable::EdgeTable (const int top_, const int height_) throw()
EdgeTable::EdgeTable (const int top_, const int height_,
const Path& path, const AffineTransform& transform) throw()
: top (top_),
height (height_),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
{
table = (int*) juce_calloc (height * lineStrideElements * sizeof (int));
table = (int*) juce_malloc (height_ * lineStrideElements * sizeof (int));
int* t = table;
for (int i = height_; --i >= 0;)
{
*t = 0;
t += lineStrideElements;
}
const int topLimit = top << 8;
const int bottomLimit = height << 8;
PathFlatteningIterator iter (path, transform);
while (iter.next())
{
int y1 = roundFloatToInt (iter.y1 * 256.0f);
int y2 = roundFloatToInt (iter.y2 * 256.0f);
if (y1 != y2)
{
y1 -= topLimit;
y2 -= topLimit;
const double startX = 256.0f * iter.x1;
const int startY = y1;
const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
int winding = -1;
if (y1 > y2)
{
swapVariables (y1, y2);
winding = 1;
}
if (y1 < 0)
y1 = 0;
if (y2 > bottomLimit)
y2 = bottomLimit;
const int stepSize = jlimit (1, 256, 256 / (1 + (int) fabs (multiplier)));
while (y1 < y2)
{
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
addEdgePoint (roundDoubleToInt (startX + multiplier * (y1 - startY)),
y1 >> 8, winding * step);
y1 += step;
}
}
}
if (! path.isUsingNonZeroWinding())
{
int* lineStart = table;
for (int i = height; --i >= 0;)
{
int* line = lineStart;
lineStart += lineStrideElements;
int num = *line;
int level = 0;
int lastCorrected = 0;
while (--num >= 0)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
*line = corrected - lastCorrected;
lastCorrected = corrected;
}
}
}
}
EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw()
: top (rectangleToAdd.getY()),
height (jmax (1, rectangleToAdd.getHeight())),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
{
jassert (! rectangleToAdd.isEmpty());
table = (int*) juce_malloc (height * lineStrideElements * sizeof (int));
*table = 0;
const int x1 = rectangleToAdd.getX();
const int x2 = rectangleToAdd.getRight();
int* t = table;
for (int i = rectangleToAdd.getHeight(); --i >= 0;)
{
t[0] = 2;
t[1] = x1;
t[2] = 256;
t[3] = x2;
t[4] = -256;
t += lineStrideElements;
}
}
EdgeTable::EdgeTable (const EdgeTable& other) throw()
@ -78936,94 +79044,47 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw
lineStart[0]++;
}
void EdgeTable::addPath (const Path& path, const AffineTransform& transform) throw()
void EdgeTable::clearLineSection (const int y, int minX, int maxX) throw()
{
const int bottomLimit = height << 8;
// int* line = table + lineStrideElements * y;
PathFlatteningIterator iter (path, transform);
}
while (iter.next())
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
{
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);
for (int i = rectTop - 1; --i >= 0;)
table [lineStrideElements * i] = 0;
for (int i = rectBottom; i < height; ++i)
table [lineStrideElements * i] = 0;
for (int i = rectTop; i < rectBottom; ++i)
{
int y1 = roundFloatToInt (iter.y1 * 256.0f) - (top << 8);
int y2 = roundFloatToInt (iter.y2 * 256.0f) - (top << 8);
if (y1 != y2)
{
const int oldY1 = y1;
const double x1 = 256.0 * iter.x1;
const double x2 = 256.0 * iter.x2;
const double multiplier = (x2 - x1) / (y2 - y1);
int winding = -1;
if (y1 > y2)
{
swapVariables (y1, y2);
winding = 1;
}
if (y1 < 0)
y1 = 0;
if (y2 > bottomLimit)
y2 = bottomLimit;
const int stepSize = jlimit (1, 256, 256 / (1 + abs ((int) multiplier)));
while (y1 < y2)
{
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
y1 >> 8, winding * step);
y1 += step;
}
}
}
if (! path.isUsingNonZeroWinding())
{
int* lineStart = table;
for (int i = height; --i >= 0;)
{
int* line = lineStart;
lineStart += lineStrideElements;
int num = *line;
int level = 0;
int lastCorrected = 0;
while (--num >= 0)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
*line = corrected - lastCorrected;
lastCorrected = corrected;
}
}
clearLineSection (i, -INT_MAX, r.getX());
clearLineSection (i, r.getRight(), INT_MAX);
}
}
/*void EdgeTable::clipToRectangle (const Rectangle& r) throw()
void EdgeTable::excludeRectangle (const Rectangle& r) throw()
{
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);
for (int i = rectTop; i < rectBottom; ++i)
clearLineSection (i, r.getX(), r.getRight());
}
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
{
}
void EdgeTable::intersectWith (const EdgeTable& other)
void EdgeTable::clipToImageAlpha (Image& image, int x, int y) throw()
{
}
void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
{
}*/
END_JUCE_NAMESPACE
/********* End of inlined file: juce_EdgeTable.cpp *********/
@ -81995,8 +82056,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPath (int clipX, int clipY, in
if (getPathBounds (clipX, clipY, clipW, clipH, path, transform, cx, cy, cw, ch))
{
EdgeTable edgeTable (0, ch);
edgeTable.addPath (path, transform.translated ((float) -cx, (float) -cy));
EdgeTable edgeTable (0, ch, path, transform.translated ((float) -cx, (float) -cy));
int stride, pixelStride;
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (cx, cy, cw, ch, stride, pixelStride);
@ -82123,8 +82183,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPathWithImage (int x, int y, i
{
if (Rectangle::intersectRectangles (x, y, w, h, imageX, imageY, sourceImage.getWidth(), sourceImage.getHeight()))
{
EdgeTable edgeTable (0, h);
edgeTable.addPath (path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
EdgeTable edgeTable (0, h, path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
int stride, pixelStride;
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (x, y, w, h, stride, pixelStride);
@ -85928,17 +85987,21 @@ void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <fl
const float scale = font->height * font->horizontalScale;
const int num = xOffsets.size();
float* const x = &(xOffsets.getReference(0));
if (font->kerning != 0)
if (num > 0)
{
for (int i = 0; i < num; ++i)
x[i] = (x[i] + i * font->kerning) * scale;
}
else
{
for (int i = 0; i < num; ++i)
x[i] *= scale;
float* const x = &(xOffsets.getReference(0));
if (font->kerning != 0)
{
for (int i = 0; i < num; ++i)
x[i] = (x[i] + i * font->kerning) * scale;
}
else
{
for (int i = 0; i < num; ++i)
x[i] *= scale;
}
}
}
@ -86069,7 +86132,7 @@ public:
g.fillAlphaChannel (*bitmap [bitmapToUse],
xOrigin [bitmapToUse] + (int) xFloor,
yOrigin [bitmapToUse] + (int) floorf (y));
yOrigin [bitmapToUse] + roundFloatToInt(y));
}
}
@ -89983,8 +90046,8 @@ Image* Path::createMaskBitmap (const AffineTransform& transform,
Image* im = new Image (Image::SingleChannel, imagePosition.getWidth(), imagePosition.getHeight(), true);
EdgeTable edgeTable (0, imagePosition.getHeight());
edgeTable.addPath (*this, transform.translated (-imagePosition.getX(), -imagePosition.getY()));
EdgeTable edgeTable (0, imagePosition.getHeight(), *this,
transform.translated (-imagePosition.getX(), -imagePosition.getY()));
int stride, pixelStride;
uint8* const pixels = (uint8*) im->lockPixelDataReadWrite (0, 0, imagePosition.getWidth(), imagePosition.getHeight(), stride, pixelStride);
@ -90473,20 +90536,47 @@ static void addEdgeAndJoint (Path& destPath,
else
{
// curved joints
float angle = atan2f (x2 - midX, y2 - midY);
float angle1 = atan2f (x2 - midX, y2 - midY);
float angle2 = atan2f (x3 - midX, y3 - midY);
while (angle < angle2 - 0.01f)
angle2 -= float_Pi * 2.0f;
const float angleIncrement = 0.1f;
destPath.lineTo (x2, y2);
while (angle > angle2)
if (fabs (angle1 - angle2) > angleIncrement)
{
destPath.lineTo (midX + width * sinf (angle),
midY + width * cosf (angle));
if (angle2 > angle1 + float_Pi
|| (angle2 < angle1 && angle2 >= angle1 - float_Pi))
{
if (angle2 > angle1)
angle2 -= float_Pi * 2.0f;
angle -= 0.1f;
jassert (angle1 <= angle2 + float_Pi);
angle1 -= angleIncrement;
while (angle1 > angle2)
{
destPath.lineTo (midX + width * sinf (angle1),
midY + width * cosf (angle1));
angle1 -= angleIncrement;
}
}
else
{
if (angle1 > angle2)
angle1 -= float_Pi * 2.0f;
jassert (angle1 >= angle2 - float_Pi);
angle1 += angleIncrement;
while (angle1 < angle2)
{
destPath.lineTo (midX + width * sinf (angle1),
midY + width * cosf (angle1));
angle1 += angleIncrement;
}
}
}
destPath.lineTo (x3, y3);
@ -261922,6 +262012,17 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
// compiled on its own).
#if JUCE_INCLUDED_FILE
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
END_JUCE_NAMESPACE
@interface NSFont (PrivateHack)
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
@end
BEGIN_JUCE_NAMESPACE
#endif
class MacTypeface : public Typeface
{
public:
@ -261973,6 +262074,9 @@ public:
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
#else
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
@ -262004,18 +262108,40 @@ public:
renderingTransform.c = 0.15f;
}
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
#endif
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
if (atsFont == 0)
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
}
else
#endif
{
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
}
#endif
}
~MacTypeface()
{
[nsFont release];
CGFontRelease (fontRef);
if (fontRef != 0)
CGFontRelease (fontRef);
delete charToGlyphMapper;
}
@ -262031,50 +262157,88 @@ public:
float getStringWidth (const String& text)
{
if (fontRef == 0)
if (fontRef == 0 || text.isEmpty())
return 0;
Array <int> glyphs (128);
createGlyphsForString (text, glyphs);
if (glyphs.size() == 0)
return 0;
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
int x = 0;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
for (int i = 0; i < glyphs.size(); ++i)
x += advances [i * 2];
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
for (int i = 0; i < length; ++i)
x += advances[i].width;
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
for (int i = 0; i < length; ++i)
x += advances[i];
juce_free (advances);
}
juce_free (glyphs);
juce_free (advances);
return x * unitsToHeightScaleFactor;
}
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
{
if (fontRef == 0)
return;
createGlyphsForString (text, glyphs);
xOffsets.add (0);
if (glyphs.size() == 0)
if (fontRef == 0 || text.isEmpty())
return;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
int x = 0;
for (int i = 0; i < glyphs.size(); ++i)
for (int i = 0; i < length; ++i)
{
x += advances [i * 2];
x += advances[i].width;
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
}
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
{
int x = 0;
for (int i = 0; i < length; ++i)
{
x += advances [i];
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (glyphs[i]);
}
}
juce_free (advances);
}
juce_free (advances);
juce_free (glyphs);
}
bool getOutlineForGlyph (int glyphNumber, Path& path)
@ -262139,15 +262303,28 @@ private:
AffineTransform pathTransform;
#endif
void createGlyphsForString (const String& text, Array <int>& dest) throw()
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
{
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
for (int i = 0; i < length; ++i)
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
return (CGGlyph*) g;
}
#endif
if (charToGlyphMapper == 0)
charToGlyphMapper = new CharToGlyphMapper (fontRef);
const juce_wchar* t = (const juce_wchar*) text;
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
return g;
}
// Reads a CGFontRef's character map table to convert unicode into glyph numbers
@ -265578,6 +265755,17 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
// compiled on its own).
#if JUCE_INCLUDED_FILE
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
END_JUCE_NAMESPACE
@interface NSFont (PrivateHack)
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
@end
BEGIN_JUCE_NAMESPACE
#endif
class MacTypeface : public Typeface
{
public:
@ -265629,6 +265817,9 @@ public:
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
#else
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
@ -265660,18 +265851,40 @@ public:
renderingTransform.c = 0.15f;
}
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
#endif
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
if (atsFont == 0)
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
}
else
#endif
{
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
}
#endif
}
~MacTypeface()
{
[nsFont release];
CGFontRelease (fontRef);
if (fontRef != 0)
CGFontRelease (fontRef);
delete charToGlyphMapper;
}
@ -265687,50 +265900,88 @@ public:
float getStringWidth (const String& text)
{
if (fontRef == 0)
if (fontRef == 0 || text.isEmpty())
return 0;
Array <int> glyphs (128);
createGlyphsForString (text, glyphs);
if (glyphs.size() == 0)
return 0;
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
int x = 0;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
for (int i = 0; i < glyphs.size(); ++i)
x += advances [i * 2];
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
for (int i = 0; i < length; ++i)
x += advances[i].width;
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
for (int i = 0; i < length; ++i)
x += advances[i];
juce_free (advances);
}
juce_free (glyphs);
juce_free (advances);
return x * unitsToHeightScaleFactor;
}
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
{
if (fontRef == 0)
return;
createGlyphsForString (text, glyphs);
xOffsets.add (0);
if (glyphs.size() == 0)
if (fontRef == 0 || text.isEmpty())
return;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
int x = 0;
for (int i = 0; i < glyphs.size(); ++i)
for (int i = 0; i < length; ++i)
{
x += advances [i * 2];
x += advances[i].width;
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
}
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
{
int x = 0;
for (int i = 0; i < length; ++i)
{
x += advances [i];
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (glyphs[i]);
}
}
juce_free (advances);
}
juce_free (advances);
juce_free (glyphs);
}
bool getOutlineForGlyph (int glyphNumber, Path& path)
@ -265795,15 +266046,28 @@ private:
AffineTransform pathTransform;
#endif
void createGlyphsForString (const String& text, Array <int>& dest) throw()
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
{
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
for (int i = 0; i < length; ++i)
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
return (CGGlyph*) g;
}
#endif
if (charToGlyphMapper == 0)
charToGlyphMapper = new CharToGlyphMapper (fontRef);
const juce_wchar* t = (const juce_wchar*) text;
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
return g;
}
// Reads a CGFontRef's character map table to convert unicode into glyph numbers
@ -266268,7 +266532,7 @@ public:
if (state->fontRef != 0)
{
CGGlyph g = glyphNumber;
CGContextShowGlyphsAtPoint (context, x, flipHeight - y, &g, 1);
CGContextShowGlyphsAtPoint (context, x, flipHeight - roundFloatToInt (y), &g, 1);
}
else
{

View file

@ -17087,15 +17087,22 @@ class JUCE_API EdgeTable
{
public:
/** Creates an empty edge table ready to have paths added.
/** Creates an edge table containing a path.
A table is created with a fixed vertical size, and only sections of paths
which lie within their range will be added to the table.
A table is created with a fixed vertical range, and only sections of the path
which lie within this range will be added to the table.
@param y the lowest y co-ordinate that the table can contain
@param y the top y co-ordinate that the table can contain
@param height the number of horizontal lines it contains
@param pathToAdd the path to add to the table
@param transform a transform to apply to the path being added
*/
EdgeTable (const int y, const int height) throw();
EdgeTable (const int y, const int height,
const Path& pathToAdd, const AffineTransform& transform) throw();
/** Creates an edge table containing a rectangle.
*/
EdgeTable (const Rectangle& rectangleToAdd) throw();
/** Creates a copy of another edge table. */
EdgeTable (const EdgeTable& other) throw();
@ -17106,21 +17113,10 @@ public:
/** Destructor. */
~EdgeTable() throw();
/** Adds edges to the table for a path.
This will add horizontal lines to the edge table for any parts of the path
which lie within the vertical bounds for which this table was created.
@param path the path to add
@param transform an optional transform to apply to the path while it's
being added
*/
void addPath (const Path& path,
const AffineTransform& transform) throw();
/*void clipToRectangle (const Rectangle& r) throw();
void intersectWith (const EdgeTable& other);
void generateFromImageAlpha (Image& image, int x, int y) throw();*/
void clipToRectangle (const Rectangle& r) throw();
void excludeRectangle (const Rectangle& r) throw();
void clipToEdgeTable (const EdgeTable& other);
void clipToImageAlpha (Image& image, int x, int y) throw();
/** Reduces the amount of space the table has allocated.
@ -17208,7 +17204,12 @@ public:
{
levelAccumulator >>= 8;
if (levelAccumulator > 0)
iterationCallback.handleEdgeTablePixel (x, jmin (0xff, levelAccumulator));
{
if (levelAccumulator >> 8)
levelAccumulator = 0xff;
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
}
}
if (++x >= clipRight)
@ -17229,8 +17230,7 @@ public:
const int numPix = endOfRun - x;
if (numPix > 0)
iterationCallback.handleEdgeTableLine (x, numPix,
jmin (correctedLevel, 0xff));
iterationCallback.handleEdgeTableLine (x, numPix, correctedLevel);
}
// save the bit at the end to be drawn next time round the loop.
@ -17261,10 +17261,10 @@ private:
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
int* table;
int top, height, maxEdgesPerLine, lineStrideElements;
bool nonZeroWinding;
void addEdgePoint (const int x, const int y, const int winding) throw();
void remapTableForNumEdges (const int newNumEdgesPerLine) throw();
void clearLineSection (const int y, int minX, int maxX) throw();
};
#endif // __JUCE_EDGETABLE_JUCEHEADER__
@ -40217,7 +40217,7 @@ public:
*/
PathFlatteningIterator (const Path& path,
const AffineTransform& transform = AffineTransform::identity,
float tolerence = 9.0f) throw();
float tolerence = 6.0f) throw();
/** Destructor. */
~PathFlatteningIterator() throw();

View file

@ -33,13 +33,121 @@ BEGIN_JUCE_NAMESPACE
const int juce_edgeTableDefaultEdgesPerLine = 32;
//==============================================================================
EdgeTable::EdgeTable (const int top_, const int height_) throw()
EdgeTable::EdgeTable (const int top_, const int height_,
const Path& path, const AffineTransform& transform) throw()
: top (top_),
height (height_),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
{
table = (int*) juce_calloc (height * lineStrideElements * sizeof (int));
table = (int*) juce_malloc (height_ * lineStrideElements * sizeof (int));
int* t = table;
for (int i = height_; --i >= 0;)
{
*t = 0;
t += lineStrideElements;
}
const int topLimit = top << 8;
const int bottomLimit = height << 8;
PathFlatteningIterator iter (path, transform);
while (iter.next())
{
int y1 = roundFloatToInt (iter.y1 * 256.0f);
int y2 = roundFloatToInt (iter.y2 * 256.0f);
if (y1 != y2)
{
y1 -= topLimit;
y2 -= topLimit;
const double startX = 256.0f * iter.x1;
const int startY = y1;
const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
int winding = -1;
if (y1 > y2)
{
swapVariables (y1, y2);
winding = 1;
}
if (y1 < 0)
y1 = 0;
if (y2 > bottomLimit)
y2 = bottomLimit;
const int stepSize = jlimit (1, 256, 256 / (1 + (int) fabs (multiplier)));
while (y1 < y2)
{
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
addEdgePoint (roundDoubleToInt (startX + multiplier * (y1 - startY)),
y1 >> 8, winding * step);
y1 += step;
}
}
}
if (! path.isUsingNonZeroWinding())
{
int* lineStart = table;
for (int i = height; --i >= 0;)
{
int* line = lineStart;
lineStart += lineStrideElements;
int num = *line;
int level = 0;
int lastCorrected = 0;
while (--num >= 0)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
*line = corrected - lastCorrected;
lastCorrected = corrected;
}
}
}
}
EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw()
: top (rectangleToAdd.getY()),
height (jmax (1, rectangleToAdd.getHeight())),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1)
{
jassert (! rectangleToAdd.isEmpty());
table = (int*) juce_malloc (height * lineStrideElements * sizeof (int));
*table = 0;
const int x1 = rectangleToAdd.getX();
const int x2 = rectangleToAdd.getRight();
int* t = table;
for (int i = rectangleToAdd.getHeight(); --i >= 0;)
{
t[0] = 2;
t[1] = x1;
t[2] = 256;
t[3] = x2;
t[4] = -256;
t += lineStrideElements;
}
}
EdgeTable::EdgeTable (const EdgeTable& other) throw()
@ -109,7 +217,6 @@ void EdgeTable::optimiseTable() throw()
remapTableForNumEdges (maxLineElements);
}
//==============================================================================
void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw()
{
jassert (y >= 0 && y < height)
@ -146,93 +253,47 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw
lineStart[0]++;
}
void EdgeTable::clearLineSection (const int y, int minX, int maxX) throw()
{
// int* line = table + lineStrideElements * y;
}
//==============================================================================
void EdgeTable::addPath (const Path& path, const AffineTransform& transform) throw()
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
{
const int bottomLimit = height << 8;
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);
PathFlatteningIterator iter (path, transform);
for (int i = rectTop - 1; --i >= 0;)
table [lineStrideElements * i] = 0;
while (iter.next())
for (int i = rectBottom; i < height; ++i)
table [lineStrideElements * i] = 0;
for (int i = rectTop; i < rectBottom; ++i)
{
int y1 = roundFloatToInt (iter.y1 * 256.0f) - (top << 8);
int y2 = roundFloatToInt (iter.y2 * 256.0f) - (top << 8);
if (y1 != y2)
{
const int oldY1 = y1;
const double x1 = 256.0 * iter.x1;
const double x2 = 256.0 * iter.x2;
const double multiplier = (x2 - x1) / (y2 - y1);
int winding = -1;
if (y1 > y2)
{
swapVariables (y1, y2);
winding = 1;
}
if (y1 < 0)
y1 = 0;
if (y2 > bottomLimit)
y2 = bottomLimit;
const int stepSize = jlimit (1, 256, 256 / (1 + abs ((int) multiplier)));
while (y1 < y2)
{
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
y1 >> 8, winding * step);
y1 += step;
}
}
}
if (! path.isUsingNonZeroWinding())
{
int* lineStart = table;
for (int i = height; --i >= 0;)
{
int* line = lineStart;
lineStart += lineStrideElements;
int num = *line;
int level = 0;
int lastCorrected = 0;
while (--num >= 0)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
*line = corrected - lastCorrected;
lastCorrected = corrected;
}
}
clearLineSection (i, -INT_MAX, r.getX());
clearLineSection (i, r.getRight(), INT_MAX);
}
}
/*void EdgeTable::clipToRectangle (const Rectangle& r) throw()
void EdgeTable::excludeRectangle (const Rectangle& r) throw()
{
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);
for (int i = rectTop; i < rectBottom; ++i)
clearLineSection (i, r.getX(), r.getRight());
}
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
{
}
void EdgeTable::intersectWith (const EdgeTable& other)
void EdgeTable::clipToImageAlpha (Image& image, int x, int y) throw()
{
}
void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
{
}*/
END_JUCE_NAMESPACE

View file

@ -42,15 +42,22 @@ class JUCE_API EdgeTable
{
public:
//==============================================================================
/** Creates an empty edge table ready to have paths added.
/** Creates an edge table containing a path.
A table is created with a fixed vertical size, and only sections of paths
which lie within their range will be added to the table.
A table is created with a fixed vertical range, and only sections of the path
which lie within this range will be added to the table.
@param y the lowest y co-ordinate that the table can contain
@param y the top y co-ordinate that the table can contain
@param height the number of horizontal lines it contains
@param pathToAdd the path to add to the table
@param transform a transform to apply to the path being added
*/
EdgeTable (const int y, const int height) throw();
EdgeTable (const int y, const int height,
const Path& pathToAdd, const AffineTransform& transform) throw();
/** Creates an edge table containing a rectangle.
*/
EdgeTable (const Rectangle& rectangleToAdd) throw();
/** Creates a copy of another edge table. */
EdgeTable (const EdgeTable& other) throw();
@ -62,21 +69,10 @@ public:
~EdgeTable() throw();
//==============================================================================
/** Adds edges to the table for a path.
This will add horizontal lines to the edge table for any parts of the path
which lie within the vertical bounds for which this table was created.
@param path the path to add
@param transform an optional transform to apply to the path while it's
being added
*/
void addPath (const Path& path,
const AffineTransform& transform) throw();
/*void clipToRectangle (const Rectangle& r) throw();
void intersectWith (const EdgeTable& other);
void generateFromImageAlpha (Image& image, int x, int y) throw();*/
void clipToRectangle (const Rectangle& r) throw();
void excludeRectangle (const Rectangle& r) throw();
void clipToEdgeTable (const EdgeTable& other);
void clipToImageAlpha (Image& image, int x, int y) throw();
/** Reduces the amount of space the table has allocated.
@ -166,7 +162,12 @@ public:
{
levelAccumulator >>= 8;
if (levelAccumulator > 0)
iterationCallback.handleEdgeTablePixel (x, jmin (0xff, levelAccumulator));
{
if (levelAccumulator >> 8)
levelAccumulator = 0xff;
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
}
}
if (++x >= clipRight)
@ -187,8 +188,7 @@ public:
const int numPix = endOfRun - x;
if (numPix > 0)
iterationCallback.handleEdgeTableLine (x, numPix,
jmin (correctedLevel, 0xff));
iterationCallback.handleEdgeTableLine (x, numPix, correctedLevel);
}
// save the bit at the end to be drawn next time round the loop.
@ -220,10 +220,10 @@ private:
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
int* table;
int top, height, maxEdgesPerLine, lineStrideElements;
bool nonZeroWinding;
void addEdgePoint (const int x, const int y, const int winding) throw();
void remapTableForNumEdges (const int newNumEdgesPerLine) throw();
void clearLineSection (const int y, int minX, int maxX) throw();
};

View file

@ -1362,8 +1362,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPath (int clipX, int clipY, in
if (getPathBounds (clipX, clipY, clipW, clipH, path, transform, cx, cy, cw, ch))
{
EdgeTable edgeTable (0, ch);
edgeTable.addPath (path, transform.translated ((float) -cx, (float) -cy));
EdgeTable edgeTable (0, ch, path, transform.translated ((float) -cx, (float) -cy));
int stride, pixelStride;
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (cx, cy, cw, ch, stride, pixelStride);
@ -1490,8 +1489,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillPathWithImage (int x, int y, i
{
if (Rectangle::intersectRectangles (x, y, w, h, imageX, imageY, sourceImage.getWidth(), sourceImage.getHeight()))
{
EdgeTable edgeTable (0, h);
edgeTable.addPath (path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
EdgeTable edgeTable (0, h, path, transform.translated ((float) (xOffset - x), (float) (yOffset - y)));
int stride, pixelStride;
uint8* const pixels = (uint8*) image.lockPixelDataReadWrite (x, y, w, h, stride, pixelStride);

View file

@ -309,17 +309,21 @@ void Font::getGlyphPositions (const String& text, Array <int>& glyphs, Array <fl
const float scale = font->height * font->horizontalScale;
const int num = xOffsets.size();
float* const x = &(xOffsets.getReference(0));
if (font->kerning != 0)
if (num > 0)
{
for (int i = 0; i < num; ++i)
x[i] = (x[i] + i * font->kerning) * scale;
}
else
{
for (int i = 0; i < num; ++i)
x[i] *= scale;
float* const x = &(xOffsets.getReference(0));
if (font->kerning != 0)
{
for (int i = 0; i < num; ++i)
x[i] = (x[i] + i * font->kerning) * scale;
}
else
{
for (int i = 0; i < num; ++i)
x[i] *= scale;
}
}
}
@ -455,7 +459,7 @@ public:
g.fillAlphaChannel (*bitmap [bitmapToUse],
xOrigin [bitmapToUse] + (int) xFloor,
yOrigin [bitmapToUse] + (int) floorf (y));
yOrigin [bitmapToUse] + roundFloatToInt(y));
}
}

View file

@ -1603,8 +1603,8 @@ Image* Path::createMaskBitmap (const AffineTransform& transform,
Image* im = new Image (Image::SingleChannel, imagePosition.getWidth(), imagePosition.getHeight(), true);
EdgeTable edgeTable (0, imagePosition.getHeight());
edgeTable.addPath (*this, transform.translated (-imagePosition.getX(), -imagePosition.getY()));
EdgeTable edgeTable (0, imagePosition.getHeight(), *this,
transform.translated (-imagePosition.getX(), -imagePosition.getY()));
int stride, pixelStride;
uint8* const pixels = (uint8*) im->lockPixelDataReadWrite (0, 0, imagePosition.getWidth(), imagePosition.getHeight(), stride, pixelStride);

View file

@ -56,7 +56,7 @@ public:
*/
PathFlatteningIterator (const Path& path,
const AffineTransform& transform = AffineTransform::identity,
float tolerence = 9.0f) throw();
float tolerence = 6.0f) throw();
/** Destructor. */
~PathFlatteningIterator() throw();

View file

@ -239,20 +239,47 @@ static void addEdgeAndJoint (Path& destPath,
else
{
// curved joints
float angle = atan2f (x2 - midX, y2 - midY);
float angle1 = atan2f (x2 - midX, y2 - midY);
float angle2 = atan2f (x3 - midX, y3 - midY);
while (angle < angle2 - 0.01f)
angle2 -= float_Pi * 2.0f;
const float angleIncrement = 0.1f;
destPath.lineTo (x2, y2);
while (angle > angle2)
if (fabs (angle1 - angle2) > angleIncrement)
{
destPath.lineTo (midX + width * sinf (angle),
midY + width * cosf (angle));
if (angle2 > angle1 + float_Pi
|| (angle2 < angle1 && angle2 >= angle1 - float_Pi))
{
if (angle2 > angle1)
angle2 -= float_Pi * 2.0f;
angle -= 0.1f;
jassert (angle1 <= angle2 + float_Pi);
angle1 -= angleIncrement;
while (angle1 > angle2)
{
destPath.lineTo (midX + width * sinf (angle1),
midY + width * cosf (angle1));
angle1 -= angleIncrement;
}
}
else
{
if (angle1 > angle2)
angle1 -= float_Pi * 2.0f;
jassert (angle1 >= angle2 - float_Pi);
angle1 += angleIncrement;
while (angle1 < angle2)
{
destPath.lineTo (midX + width * sinf (angle1),
midY + width * cosf (angle1));
angle1 += angleIncrement;
}
}
}
destPath.lineTo (x3, y3);

View file

@ -355,7 +355,7 @@ public:
if (state->fontRef != 0)
{
CGGlyph g = glyphNumber;
CGContextShowGlyphsAtPoint (context, x, flipHeight - y, &g, 1);
CGContextShowGlyphsAtPoint (context, x, flipHeight - roundFloatToInt (y), &g, 1);
}
else
{

View file

@ -27,6 +27,16 @@
// compiled on its own).
#if JUCE_INCLUDED_FILE
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
END_JUCE_NAMESPACE
@interface NSFont (PrivateHack)
- (NSGlyph) _defaultGlyphForChar: (unichar) theChar;
@end
BEGIN_JUCE_NAMESPACE
#endif
//==============================================================================
class MacTypeface : public Typeface
@ -80,6 +90,9 @@ public:
fontRef = CGFontCreateWithFontName ((CFStringRef) fontName);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
#else
nsFont = [NSFont fontWithName: juceStringToNS (font.getTypefaceName()) size: 1024];
@ -111,18 +124,40 @@ public:
renderingTransform.c = 0.15f;
}
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
#endif
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
if (atsFont == 0)
atsFont = ATSFontFindFromPostScriptName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
fontRef = CGFontCreateWithPlatformFont ((void*) &atsFont);
const float totalHeight = fabsf ([nsFont ascender]) + fabsf([nsFont descender]);
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = 1024.0f / totalHeight;
}
else
#endif
{
fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]);
const int totalHeight = abs (CGFontGetAscent (fontRef)) + abs (CGFontGetDescent (fontRef));
unitsToHeightScaleFactor = 1.0f / totalHeight;
fontHeightToCGSizeFactor = CGFontGetUnitsPerEm (fontRef) / (float) totalHeight;
}
#endif
}
~MacTypeface()
{
[nsFont release];
CGFontRelease (fontRef);
if (fontRef != 0)
CGFontRelease (fontRef);
delete charToGlyphMapper;
}
@ -138,50 +173,88 @@ public:
float getStringWidth (const String& text)
{
if (fontRef == 0)
if (fontRef == 0 || text.isEmpty())
return 0;
Array <int> glyphs (128);
createGlyphsForString (text, glyphs);
if (glyphs.size() == 0)
return 0;
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
int x = 0;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
for (int i = 0; i < glyphs.size(); ++i)
x += advances [i * 2];
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
for (int i = 0; i < length; ++i)
x += advances[i].width;
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
for (int i = 0; i < length; ++i)
x += advances[i];
juce_free (advances);
}
juce_free (glyphs);
juce_free (advances);
return x * unitsToHeightScaleFactor;
}
void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets)
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
{
if (fontRef == 0)
return;
createGlyphsForString (text, glyphs);
xOffsets.add (0);
if (glyphs.size() == 0)
if (fontRef == 0 || text.isEmpty())
return;
int* const advances = (int*) juce_malloc (glyphs.size() * 2 * sizeof (int));
const int length = text.length();
CGGlyph* const glyphs = createGlyphsForString (text, length);
if (CGFontGetGlyphAdvances (fontRef, (CGGlyph*) &glyphs.getReference(0), glyphs.size() * 2, advances))
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize));
[nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length];
int x = 0;
for (int i = 0; i < glyphs.size(); ++i)
for (int i = 0; i < length; ++i)
{
x += advances [i * 2];
x += advances[i].width;
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (((NSGlyph*) glyphs)[i]);
}
juce_free (advances);
}
else
#endif
{
int* const advances = (int*) juce_malloc (length * sizeof (int));
if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances))
{
int x = 0;
for (int i = 0; i < length; ++i)
{
x += advances [i];
xOffsets.add (x * unitsToHeightScaleFactor);
resultGlyphs.add (glyphs[i]);
}
}
juce_free (advances);
}
juce_free (advances);
juce_free (glyphs);
}
bool getOutlineForGlyph (int glyphNumber, Path& path)
@ -247,15 +320,28 @@ private:
AffineTransform pathTransform;
#endif
void createGlyphsForString (const String& text, Array <int>& dest) throw()
CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw()
{
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length);
for (int i = 0; i < length; ++i)
g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]];
return (CGGlyph*) g;
}
#endif
if (charToGlyphMapper == 0)
charToGlyphMapper = new CharToGlyphMapper (fontRef);
const juce_wchar* t = (const juce_wchar*) text;
CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length);
while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
return g;
}
// Reads a CGFontRef's character map table to convert unicode into glyph numbers