Browse Source

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

tags/2021-05-28
Julian Storer 16 years ago
parent
commit
ca727ec2bb
12 changed files with 783 additions and 343 deletions
  1. +1
    -1
      extras/juce demo/src/demos/FontsAndTextDemo.cpp
  2. +425
    -161
      juce_amalgamated.cpp
  3. +25
    -25
      juce_amalgamated.h
  4. +134
    -73
      src/gui/graphics/contexts/juce_EdgeTable.cpp
  5. +24
    -24
      src/gui/graphics/contexts/juce_EdgeTable.h
  6. +2
    -4
      src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp
  7. +14
    -10
      src/gui/graphics/fonts/juce_Font.cpp
  8. +2
    -2
      src/gui/graphics/geometry/juce_Path.cpp
  9. +1
    -1
      src/gui/graphics/geometry/juce_PathIterator.h
  10. +36
    -9
      src/gui/graphics/geometry/juce_PathStrokeType.cpp
  11. +1
    -1
      src/native/mac/juce_mac_CoreGraphicsContext.mm
  12. +118
    -32
      src/native/mac/juce_mac_Fonts.mm

+ 1
- 1
extras/juce demo/src/demos/FontsAndTextDemo.cpp 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);


+ 425
- 161
juce_amalgamated.cpp 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,93 +79044,46 @@ 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;

PathFlatteningIterator iter (path, transform);
// int* line = table + lineStrideElements * y;

while (iter.next())
{
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));
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
{
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);

addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
y1 >> 8, winding * step);
for (int i = rectTop - 1; --i >= 0;)
table [lineStrideElements * i] = 0;

y1 += step;
}
}
}
for (int i = rectBottom; i < height; ++i)
table [lineStrideElements * i] = 0;

if (! path.isUsingNonZeroWinding())
for (int i = rectTop; i < rectBottom; ++i)
{
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::intersectWith (const EdgeTable& other)
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
{
}

void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
void EdgeTable::clipToImageAlpha (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)
{
for (int i = 0; i < num; ++i)
x[i] = (x[i] + i * font->kerning) * scale;
}
else
if (num > 0)
{
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;

jassert (angle1 <= angle2 + float_Pi);

angle1 -= angleIncrement;
while (angle1 > angle2)
{
destPath.lineTo (midX + width * sinf (angle1),
midY + width * cosf (angle1));

angle -= 0.1f;
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]);
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);

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;
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);

for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);

while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
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]);
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);

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;
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);

for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);

while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
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
{


+ 25
- 25
juce_amalgamated.h 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();


+ 134
- 73
src/gui/graphics/contexts/juce_EdgeTable.cpp 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::addPath (const Path& path, const AffineTransform& transform) throw()
void EdgeTable::clearLineSection (const int y, int minX, int maxX) throw()
{
const int bottomLimit = height << 8;
PathFlatteningIterator iter (path, transform);
// int* line = table + lineStrideElements * y;
while (iter.next())
{
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));
//==============================================================================
void EdgeTable::clipToRectangle (const Rectangle& r) throw()
{
const int rectTop = jmax (0, r.getY() - top);
const int rectBottom = jmin (height, r.getBottom() - top);
addEdgePoint (roundDoubleToInt (x1 + multiplier * (y1 - oldY1)),
y1 >> 8, winding * step);
for (int i = rectTop - 1; --i >= 0;)
table [lineStrideElements * i] = 0;
y1 += step;
}
}
}
for (int i = rectBottom; i < height; ++i)
table [lineStrideElements * i] = 0;
if (! path.isUsingNonZeroWinding())
for (int i = rectTop; i < rectBottom; ++i)
{
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::intersectWith (const EdgeTable& other)
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
{
}
void EdgeTable::generateFromImageAlpha (Image& image, int x, int y) throw()
void EdgeTable::clipToImageAlpha (Image& image, int x, int y) throw()
{
}*/
}
END_JUCE_NAMESPACE

+ 24
- 24
src/gui/graphics/contexts/juce_EdgeTable.h 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();
};


+ 2
- 4
src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp 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);


+ 14
- 10
src/gui/graphics/fonts/juce_Font.cpp 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));
}
}


+ 2
- 2
src/gui/graphics/geometry/juce_Path.cpp 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);


+ 1
- 1
src/gui/graphics/geometry/juce_PathIterator.h 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();


+ 36
- 9
src/gui/graphics/geometry/juce_PathStrokeType.cpp 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));
angle -= 0.1f;
if (angle2 > angle1 + float_Pi
|| (angle2 < angle1 && angle2 >= angle1 - float_Pi))
{
if (angle2 > angle1)
angle2 -= 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;
}
}
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);


+ 1
- 1
src/native/mac/juce_mac_CoreGraphicsContext.mm 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
{


+ 118
- 32
src/native/mac/juce_mac_Fonts.mm 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]);
#if SUPPORT_10_4_FONTS
if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE)
{
ATSFontRef atsFont = ATSFontFindFromName ((CFStringRef) [nsFont fontName], kATSOptionFlagsDefault);
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;
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));
juce_free (advances);
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 (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);
for (int i = 0; i < length; ++i)
g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]);
while (*t != 0)
dest.add (charToGlyphMapper->getGlyphForCharacter (*t++));
return g;
}
// Reads a CGFontRef's character map table to convert unicode into glyph numbers


Loading…
Cancel
Save