Browse Source

Rewrote the Mac font loading code to use Cocoa instead of Carbon APIs.

tags/2021-05-28
jules 16 years ago
parent
commit
59fd199164
3 changed files with 278 additions and 669 deletions
  1. +107
    -301
      build/macosx/platform_specific_code/juce_mac_Fonts.mm
  2. +72
    -73
      build/macosx/platform_specific_code/juce_mac_NativeIncludes.h
  3. +99
    -295
      juce_amalgamated.cpp

+ 107
- 301
build/macosx/platform_specific_code/juce_mac_Fonts.mm View File

@@ -33,129 +33,46 @@
// compiled on its own). // compiled on its own).
#ifdef JUCE_INCLUDED_FILE #ifdef JUCE_INCLUDED_FILE
//==============================================================================
static OSStatus pascal CubicMoveTo (const Float32Point *pt,
void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->startNewSubPath (pt->x, pt->y);
return noErr;
}
static OSStatus pascal CubicLineTo (const Float32Point *pt,
void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->lineTo (pt->x, pt->y);
return noErr;
}
static OSStatus pascal CubicCurveTo (const Float32Point *pt1,
const Float32Point *pt2,
const Float32Point *pt3,
void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->cubicTo (pt1->x, pt1->y,
pt2->x, pt2->y,
pt3->x, pt3->y);
return noErr;
}
static OSStatus pascal CubicClosePath (void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->closeSubPath();
return noErr;
}
//============================================================================== //==============================================================================
class ATSFontHelper
class FontHelper
{ {
ATSUFontID fontId;
ATSUStyle style;
ATSCubicMoveToUPP moveToProc;
ATSCubicLineToUPP lineToProc;
ATSCubicCurveToUPP curveToProc;
ATSCubicClosePathUPP closePathProc;
float totalSize, ascent;
TextToUnicodeInfo encodingInfo;
NSFont* font;
public: public:
String name; String name;
bool isBold, isItalic; bool isBold, isItalic;
float fontSize;
float fontSize, totalSize, ascent;
int refCount; int refCount;
ATSFontHelper (const String& name_,
const bool bold_,
const bool italic_,
const float size_)
: fontId (0),
FontHelper (const String& name_,
const bool bold_,
const bool italic_,
const float size_)
: font (0),
name (name_), name (name_),
isBold (bold_), isBold (bold_),
isItalic (italic_), isItalic (italic_),
fontSize (size_), fontSize (size_),
refCount (1) refCount (1)
{ {
const char* const nameUtf8 = name_.toUTF8();
ATSUFindFontFromName (const_cast <char*> (nameUtf8),
strlen (nameUtf8),
kFontFullName,
kFontNoPlatformCode,
kFontNoScriptCode,
kFontNoLanguageCode,
&fontId);
ATSUCreateStyle (&style);
ATSUAttributeTag attTypes[] = { kATSUFontTag,
kATSUQDBoldfaceTag,
kATSUQDItalicTag,
kATSUSizeTag };
ByteCount attSizes[] = { sizeof (ATSUFontID),
sizeof (Boolean),
sizeof (Boolean),
sizeof (Fixed) };
Boolean bold = bold_, italic = italic_;
Fixed size = X2Fix (size_);
ATSUAttributeValuePtr attValues[] = { &fontId,
&bold,
&italic,
&size };
ATSUSetAttributes (style, 4, attTypes, attSizes, attValues);
moveToProc = NewATSCubicMoveToUPP (CubicMoveTo);
lineToProc = NewATSCubicLineToUPP (CubicLineTo);
curveToProc = NewATSCubicCurveToUPP (CubicCurveTo);
closePathProc = NewATSCubicClosePathUPP (CubicClosePath);
ascent = 0.0f;
float kern, descent = 0.0f;
getPathAndKerning (T('N'), T('O'), 0, kern, &ascent, &descent);
totalSize = ascent + descent;
font = [NSFont fontWithName: juceStringToNS (name_) size: size_];
if (italic_)
font = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSItalicFontMask];
if (bold_)
font = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSBoldFontMask];
[font retain];
ascent = fabsf ([font ascender]);
totalSize = ascent + fabsf ([font descender]);
} }
~ATSFontHelper()
~FontHelper()
{ {
ATSUDisposeStyle (style);
DisposeATSCubicMoveToUPP (moveToProc);
DisposeATSCubicLineToUPP (lineToProc);
DisposeATSCubicCurveToUPP (curveToProc);
DisposeATSCubicClosePathUPP (closePathProc);
[font release];
} }
bool getPathAndKerning (const juce_wchar char1, bool getPathAndKerning (const juce_wchar char1,
@@ -165,128 +82,65 @@ public:
float* ascent, float* ascent,
float* descent) float* descent)
{ {
bool ok = false;
UniChar buffer[4];
buffer[0] = T(' ');
buffer[1] = char1;
buffer[2] = char2;
buffer[3] = 0;
UniCharCount count = kATSUToTextEnd;
ATSUTextLayout layout;
OSStatus err = ATSUCreateTextLayoutWithTextPtr (buffer,
0,
2,
2,
1,
&count,
&style,
&layout);
if (err == noErr)
const ScopedAutoReleasePool pool;
if (font == 0
|| ! [[font coveredCharacterSet] longCharacterIsMember: (UTF32Char) char1])
return false;
String chars;
chars << ' ' << char1 << char2;
NSTextStorage* textStorage = [[[NSTextStorage alloc] initWithString: juceStringToNS (chars)] autorelease];
NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
NSTextContainer* textContainer = [[[NSTextContainer alloc] init] autorelease];
[layoutManager addTextContainer: textContainer];
[textStorage addLayoutManager: layoutManager];
[textStorage setFont: font];
unsigned int glyphIndex = [layoutManager glyphRangeForCharacterRange: NSMakeRange (1, 1)
actualCharacterRange: 0].location;
NSPoint p1 = [layoutManager locationForGlyphAtIndex: glyphIndex];
NSPoint p2 = [layoutManager locationForGlyphAtIndex: glyphIndex + 1];
kerning = p2.x - p1.x;
if (ascent != 0)
*ascent = this->ascent;
if (descent != 0)
*descent = fabsf ([font descender]);
if (path != 0)
{ {
ATSUSetTransientFontMatching (layout, true);
ATSLayoutRecord* layoutRecords;
ItemCount numRecords;
Fixed* deltaYs;
ItemCount numDeltaYs;
ATSUDirectGetLayoutDataArrayPtrFromTextLayout (layout,
0,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void**) &layoutRecords,
&numRecords);
ATSUDirectGetLayoutDataArrayPtrFromTextLayout (layout,
0,
kATSUDirectDataBaselineDeltaFixedArray,
(void**) &deltaYs,
&numDeltaYs);
if (numRecords > 2)
{
kerning = (float) (Fix2X (layoutRecords[2].realPos)
- Fix2X (layoutRecords[1].realPos));
if (ascent != 0)
{
ATSUTextMeasurement asc;
ByteCount actualSize;
NSBezierPath* bez = [NSBezierPath bezierPath];
[bez moveToPoint: NSMakePoint (0, 0)];
[bez appendBezierPathWithGlyph: [layoutManager glyphAtIndex: glyphIndex]
inFont: font];
ATSUGetLineControl (layout,
0,
kATSULineAscentTag,
sizeof (ATSUTextMeasurement),
&asc,
&actualSize);
*ascent = (float) Fix2X (asc);
}
if (descent != 0)
{
ATSUTextMeasurement desc;
ByteCount actualSize;
ATSUGetLineControl (layout,
0,
kATSULineDescentTag,
sizeof (ATSUTextMeasurement),
&desc,
&actualSize);
*descent = (float) Fix2X (desc);
}
if (path != 0)
{
OSStatus callbackResult;
ok = (ATSUGlyphGetCubicPaths (style,
layoutRecords[1].glyphID,
moveToProc,
lineToProc,
curveToProc,
closePathProc,
(void*) path,
&callbackResult) == noErr);
if (numDeltaYs > 0 && ok)
{
const float dy = (float) Fix2X (deltaYs[1]);
path->applyTransform (AffineTransform::translation (0.0f, dy));
}
}
else
for (int i = 0; i < [bez elementCount]; ++i)
{
NSPoint p[3];
switch ([bez elementAtIndex: i associatedPoints: p])
{ {
ok = true;
case NSMoveToBezierPathElement:
path->startNewSubPath (p[0].x, -p[0].y);
break;
case NSLineToBezierPathElement:
path->lineTo (p[0].x, -p[0].y);
break;
case NSCurveToBezierPathElement:
path->cubicTo (p[0].x, -p[0].y, p[1].x, -p[1].y, p[2].x, -p[2].y);
break;
case NSClosePathBezierPathElement:
path->closeSubPath();
break;
default:
jassertfalse
break;
} }
} }
if (deltaYs != 0)
ATSUDirectReleaseLayoutDataArrayPtr (0, kATSUDirectDataBaselineDeltaFixedArray,
(void**) &deltaYs);
if (layoutRecords != 0)
ATSUDirectReleaseLayoutDataArrayPtr (0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void**) &layoutRecords);
ATSUDisposeTextLayout (layout);
} }
return kerning;
}
float getAscent()
{
return ascent;
}
float getTotalHeight()
{
return totalSize;
return kerning != 0;
} }
juce_wchar getDefaultChar() juce_wchar getDefaultChar()
@@ -296,35 +150,35 @@ public:
}; };
//============================================================================== //==============================================================================
class ATSFontHelperCache : public Timer,
public DeletedAtShutdown
class FontHelperCache : public Timer,
public DeletedAtShutdown
{ {
VoidArray cache; VoidArray cache;
public: public:
ATSFontHelperCache()
FontHelperCache()
{ {
} }
~ATSFontHelperCache()
~FontHelperCache()
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
delete f; delete f;
} }
clearSingletonInstance(); clearSingletonInstance();
} }
ATSFontHelper* getFont (const String& name,
const bool bold,
const bool italic,
const float size = 1024)
FontHelper* getFont (const String& name,
const bool bold,
const bool italic,
const float size = 1024)
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
if (f->name == name if (f->name == name
&& f->isBold == bold && f->isBold == bold
@@ -336,16 +190,16 @@ public:
} }
} }
ATSFontHelper* const f = new ATSFontHelper (name, bold, italic, size);
FontHelper* const f = new FontHelper (name, bold, italic, size);
cache.add (f); cache.add (f);
return f; return f;
} }
void releaseFont (ATSFontHelper* f)
void releaseFont (FontHelper* f)
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f2 = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f2 = (FontHelper*) cache.getUnchecked(i);
if (f == f2) if (f == f2)
{ {
@@ -365,7 +219,7 @@ public:
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
if (f->refCount == 0) if (f->refCount == 0)
{ {
@@ -378,10 +232,10 @@ public:
delete this; delete this;
} }
juce_DeclareSingleton_SingleThreaded_Minimal (ATSFontHelperCache)
juce_DeclareSingleton_SingleThreaded_Minimal (FontHelperCache)
}; };
juce_ImplementSingleton_SingleThreaded (ATSFontHelperCache)
juce_ImplementSingleton_SingleThreaded (FontHelperCache)
//============================================================================== //==============================================================================
void Typeface::initialiseTypefaceCharacteristics (const String& fontName, void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
@@ -392,11 +246,11 @@ void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
// This method is only safe to be called from the normal UI thread.. // This method is only safe to be called from the normal UI thread..
jassert (MessageManager::getInstance()->isThisTheMessageThread()); jassert (MessageManager::getInstance()->isThisTheMessageThread());
ATSFontHelper* const helper = ATSFontHelperCache::getInstance()
->getFont (fontName, bold, italic);
FontHelper* const helper = FontHelperCache::getInstance()
->getFont (fontName, bold, italic);
clear(); clear();
setAscent (helper->getAscent() / helper->getTotalHeight());
setAscent (helper->ascent / helper->totalSize);
setName (fontName); setName (fontName);
setDefaultCharacter (helper->getDefaultChar()); setDefaultCharacter (helper->getDefaultChar());
setBold (bold); setBold (bold);
@@ -408,7 +262,7 @@ void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
jassertfalse jassertfalse
} }
ATSFontHelperCache::getInstance()->releaseFont (helper);
FontHelperCache::getInstance()->releaseFont (helper);
} }
bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw() bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
@@ -416,8 +270,8 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
// This method is only safe to be called from the normal UI thread.. // This method is only safe to be called from the normal UI thread..
jassert (MessageManager::getInstance()->isThisTheMessageThread()); jassert (MessageManager::getInstance()->isThisTheMessageThread());
ATSFontHelper* const helper = ATSFontHelperCache::getInstance()
->getFont (getName(), isBold(), isItalic());
FontHelper* const helper = FontHelperCache::getInstance()
->getFont (getName(), isBold(), isItalic());
Path path; Path path;
float width; float width;
@@ -425,10 +279,10 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0)) if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0))
{ {
path.applyTransform (AffineTransform::scale (1.0f / helper->getTotalHeight(),
1.0f / helper->getTotalHeight()));
path.applyTransform (AffineTransform::scale (1.0f / helper->totalSize,
1.0f / helper->totalSize));
addGlyph (character, path, width / helper->getTotalHeight());
addGlyph (character, path, width / helper->totalSize);
for (int i = 0; i < glyphs.size(); ++i) for (int i = 0; i < glyphs.size(); ++i)
{ {
@@ -437,7 +291,7 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
float kerning; float kerning;
if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0)) if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0))
{ {
kerning = (kerning - width) / helper->getTotalHeight();
kerning = (kerning - width) / helper->totalSize;
if (kerning != 0) if (kerning != 0)
addKerningPair (character, g->getCharacter(), kerning); addKerningPair (character, g->getCharacter(), kerning);
@@ -445,7 +299,7 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0)) if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0))
{ {
kerning = kerning / helper->getTotalHeight() - g->width;
kerning = kerning / helper->totalSize - g->width;
if (kerning != 0) if (kerning != 0)
addKerningPair (g->getCharacter(), character, kerning); addKerningPair (g->getCharacter(), character, kerning);
@@ -455,68 +309,20 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
foundOne = true; foundOne = true;
} }
ATSFontHelperCache::getInstance()->releaseFont (helper);
FontHelperCache::getInstance()->releaseFont (helper);
return foundOne; return foundOne;
} }
//==============================================================================
const StringArray Font::findAllTypefaceNames() throw() const StringArray Font::findAllTypefaceNames() throw()
{ {
StringArray names; StringArray names;
ATSFontIterator iter;
if (ATSFontIteratorCreate (kATSFontContextGlobal,
0,
0,
kATSOptionFlagsRestrictedScope,
&iter) == noErr)
{
ATSFontRef font;
while (ATSFontIteratorNext (iter, &font) == noErr)
{
CFStringRef name;
if (ATSFontGetName (font,
kATSOptionFlagsDefault,
&name) == noErr)
{
const String nm (PlatformUtilities::cfStringToJuceString (name));
if (nm.isNotEmpty())
names.add (nm);
CFRelease (name);
}
}
const ScopedAutoReleasePool pool;
NSArray* fonts = [[NSFontManager sharedFontManager] availableFontFamilies];
ATSFontIteratorRelease (&iter);
}
// Use some totuous logic to eliminate bold/italic versions of fonts that we've already got
// a plain version of. This is only necessary because of Carbon's total lack of support
// for dealing with font families...
for (int j = names.size(); --j >= 0;)
{
const char* const endings[] = { " bold", " italic", " bold italic", " bolditalic",
" oblque", " bold oblique", " boldoblique" };
for (int i = 0; i < numElementsInArray (endings); ++i)
{
const String ending (endings[i]);
if (names[j].endsWithIgnoreCase (ending))
{
const String root (names[j].dropLastCharacters (ending.length()).trimEnd());
if (names.contains (root)
|| names.contains (root + T(" plain"), true))
{
names.remove (j);
break;
}
}
}
}
for (int i = 0; i < [fonts count]; ++i)
names.add (nsStringToJuce ((NSString*) [fonts objectAtIndex: i]));
names.sort (true); names.sort (true);
return names; return names;


+ 72
- 73
build/macosx/platform_specific_code/juce_mac_NativeIncludes.h View File

@@ -1,73 +1,72 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-7 by Raw Material Software ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
------------------------------------------------------------------------------
If you'd like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
#ifndef __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__
#define __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__
/*
This file wraps together all the mac-specific code, so that
we can include all the native headers just once, and compile all our
platform-specific stuff in one big lump, keeping it out of the way of
the rest of the codebase.
*/
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
#import <Cocoa/Cocoa.h>
#import <CoreAudio/HostTime.h>
#import <CoreAudio/AudioHardware.h>
#import <CoreMIDI/MIDIServices.h>
#import <QTKit/QTKit.h>
#import <WebKit/WebKit.h>
#import <DiscRecording/DiscRecording.h>
#import <ApplicationServices/ApplicationServices.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDLib.h>
#import <IOKit/hid/IOHIDKeys.h>
#import <IOKit/network/IOEthernetInterface.h>
#import <IOKit/network/IONetworkInterface.h>
#import <IOKit/network/IOEthernetController.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <fnmatch.h>
#include <utime.h>
#if MACOS_10_4_OR_EARLIER
#include <GLUT/glut.h>
#endif
#endif // __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__
/*
==============================================================================

This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-7 by Raw Material Software ltd.

------------------------------------------------------------------------------

JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA

------------------------------------------------------------------------------

If you'd like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.

==============================================================================
*/

#ifndef __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__
#define __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__

/*
This file wraps together all the mac-specific code, so that
we can include all the native headers just once, and compile all our
platform-specific stuff in one big lump, keeping it out of the way of
the rest of the codebase.
*/

#include "../../../src/juce_core/basics/juce_StandardHeader.h"

#import <Cocoa/Cocoa.h>
#import <CoreAudio/HostTime.h>
#import <CoreAudio/AudioHardware.h>
#import <CoreMIDI/MIDIServices.h>
#import <QTKit/QTKit.h>
#import <WebKit/WebKit.h>
#import <DiscRecording/DiscRecording.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDLib.h>
#import <IOKit/hid/IOHIDKeys.h>
#import <IOKit/network/IOEthernetInterface.h>
#import <IOKit/network/IONetworkInterface.h>
#import <IOKit/network/IOEthernetController.h>
#import <IOKit/pwr_mgt/IOPMLib.h>

#include <sys/sysctl.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <fnmatch.h>
#include <utime.h>

#if MACOS_10_4_OR_EARLIER
#include <GLUT/glut.h>
#endif

#endif // __JUCE_MAC_NATIVEINCLUDES_JUCEHEADER__

+ 99
- 295
juce_amalgamated.cpp View File

@@ -593,7 +593,6 @@
#import <QTKit/QTKit.h> #import <QTKit/QTKit.h>
#import <WebKit/WebKit.h> #import <WebKit/WebKit.h>
#import <DiscRecording/DiscRecording.h> #import <DiscRecording/DiscRecording.h>
#import <ApplicationServices/ApplicationServices.h>
#import <IOKit/IOKitLib.h> #import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h> #import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDLib.h> #import <IOKit/hid/IOHIDLib.h>
@@ -257180,7 +257179,7 @@ public:
} }


if (! outputDevice->setParameters ((unsigned int) sampleRate, if (! outputDevice->setParameters ((unsigned int) sampleRate,
jmax (minChansOut, currentOutputChans.getHighestBit() + 1),
jlimit (minChansOut, maxChansOut, currentOutputChans.getHighestBit() + 1),
bufferSize)) bufferSize))
{ {
error = outputDevice->error; error = outputDevice->error;
@@ -257201,7 +257200,7 @@ public:
} }


if (! inputDevice->setParameters ((unsigned int) sampleRate, if (! inputDevice->setParameters ((unsigned int) sampleRate,
jmax (minChansIn, currentInputChans.getHighestBit() + 1),
jlimit (minChansIn, maxChansIn, currentInputChans.getHighestBit() + 1),
bufferSize)) bufferSize))
{ {
error = inputDevice->error; error = inputDevice->error;
@@ -269299,127 +269298,44 @@ const String AudioCDBurner::burn (JUCE_NAMESPACE::AudioCDBurner::BurnProgressLis
// compiled on its own). // compiled on its own).
#ifdef JUCE_INCLUDED_FILE #ifdef JUCE_INCLUDED_FILE


static OSStatus pascal CubicMoveTo (const Float32Point *pt,
void* callBackDataPtr)
class FontHelper
{ {
Path* const p = (Path*) callBackDataPtr;
p->startNewSubPath (pt->x, pt->y);

return noErr;
}

static OSStatus pascal CubicLineTo (const Float32Point *pt,
void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->lineTo (pt->x, pt->y);

return noErr;
}

static OSStatus pascal CubicCurveTo (const Float32Point *pt1,
const Float32Point *pt2,
const Float32Point *pt3,
void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->cubicTo (pt1->x, pt1->y,
pt2->x, pt2->y,
pt3->x, pt3->y);

return noErr;
}

static OSStatus pascal CubicClosePath (void* callBackDataPtr)
{
Path* const p = (Path*) callBackDataPtr;
p->closeSubPath();

return noErr;
}

class ATSFontHelper
{
ATSUFontID fontId;
ATSUStyle style;

ATSCubicMoveToUPP moveToProc;
ATSCubicLineToUPP lineToProc;
ATSCubicCurveToUPP curveToProc;
ATSCubicClosePathUPP closePathProc;

float totalSize, ascent;

TextToUnicodeInfo encodingInfo;
NSFont* font;


public: public:
String name; String name;
bool isBold, isItalic; bool isBold, isItalic;
float fontSize;
float fontSize, totalSize, ascent;
int refCount; int refCount;


ATSFontHelper (const String& name_,
const bool bold_,
const bool italic_,
const float size_)
: fontId (0),
FontHelper (const String& name_,
const bool bold_,
const bool italic_,
const float size_)
: font (0),
name (name_), name (name_),
isBold (bold_), isBold (bold_),
isItalic (italic_), isItalic (italic_),
fontSize (size_), fontSize (size_),
refCount (1) refCount (1)
{ {
const char* const nameUtf8 = name_.toUTF8();

ATSUFindFontFromName (const_cast <char*> (nameUtf8),
strlen (nameUtf8),
kFontFullName,
kFontNoPlatformCode,
kFontNoScriptCode,
kFontNoLanguageCode,
&fontId);
font = [NSFont fontWithName: juceStringToNS (name_) size: size_];


ATSUCreateStyle (&style);
if (italic_)
font = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSItalicFontMask];


ATSUAttributeTag attTypes[] = { kATSUFontTag,
kATSUQDBoldfaceTag,
kATSUQDItalicTag,
kATSUSizeTag };
if (bold_)
font = [[NSFontManager sharedFontManager] convertFont: font toHaveTrait: NSBoldFontMask];


ByteCount attSizes[] = { sizeof (ATSUFontID),
sizeof (Boolean),
sizeof (Boolean),
sizeof (Fixed) };
[font retain];


Boolean bold = bold_, italic = italic_;
Fixed size = X2Fix (size_);

ATSUAttributeValuePtr attValues[] = { &fontId,
&bold,
&italic,
&size };

ATSUSetAttributes (style, 4, attTypes, attSizes, attValues);

moveToProc = NewATSCubicMoveToUPP (CubicMoveTo);
lineToProc = NewATSCubicLineToUPP (CubicLineTo);
curveToProc = NewATSCubicCurveToUPP (CubicCurveTo);
closePathProc = NewATSCubicClosePathUPP (CubicClosePath);

ascent = 0.0f;
float kern, descent = 0.0f;
getPathAndKerning (T('N'), T('O'), 0, kern, &ascent, &descent);
totalSize = ascent + descent;
ascent = fabsf ([font ascender]);
totalSize = ascent + fabsf ([font descender]);
} }


~ATSFontHelper()
~FontHelper()
{ {
ATSUDisposeStyle (style);

DisposeATSCubicMoveToUPP (moveToProc);
DisposeATSCubicLineToUPP (lineToProc);
DisposeATSCubicCurveToUPP (curveToProc);
DisposeATSCubicClosePathUPP (closePathProc);
[font release];
} }


bool getPathAndKerning (const juce_wchar char1, bool getPathAndKerning (const juce_wchar char1,
@@ -269429,128 +269345,65 @@ public:
float* ascent, float* ascent,
float* descent) float* descent)
{ {
bool ok = false;

UniChar buffer[4];
buffer[0] = T(' ');
buffer[1] = char1;
buffer[2] = char2;
buffer[3] = 0;

UniCharCount count = kATSUToTextEnd;
ATSUTextLayout layout;
OSStatus err = ATSUCreateTextLayoutWithTextPtr (buffer,
0,
2,
2,
1,
&count,
&style,
&layout);
if (err == noErr)
{
ATSUSetTransientFontMatching (layout, true);

ATSLayoutRecord* layoutRecords;
ItemCount numRecords;
Fixed* deltaYs;
ItemCount numDeltaYs;

ATSUDirectGetLayoutDataArrayPtrFromTextLayout (layout,
0,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void**) &layoutRecords,
&numRecords);

ATSUDirectGetLayoutDataArrayPtrFromTextLayout (layout,
0,
kATSUDirectDataBaselineDeltaFixedArray,
(void**) &deltaYs,
&numDeltaYs);
const ScopedAutoReleasePool pool;


if (numRecords > 2)
{
kerning = (float) (Fix2X (layoutRecords[2].realPos)
- Fix2X (layoutRecords[1].realPos));
if (font == 0
|| ! [[font coveredCharacterSet] longCharacterIsMember: (UTF32Char) char1])
return false;


if (ascent != 0)
{
ATSUTextMeasurement asc;
ByteCount actualSize;
String chars;
chars << ' ' << char1 << char2;
NSTextStorage* textStorage = [[[NSTextStorage alloc] initWithString: juceStringToNS (chars)] autorelease];
NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
NSTextContainer* textContainer = [[[NSTextContainer alloc] init] autorelease];
[layoutManager addTextContainer: textContainer];
[textStorage addLayoutManager: layoutManager];
[textStorage setFont: font];


ATSUGetLineControl (layout,
0,
kATSULineAscentTag,
sizeof (ATSUTextMeasurement),
&asc,
&actualSize);
unsigned int glyphIndex = [layoutManager glyphRangeForCharacterRange: NSMakeRange (1, 1)
actualCharacterRange: 0].location;
NSPoint p1 = [layoutManager locationForGlyphAtIndex: glyphIndex];
NSPoint p2 = [layoutManager locationForGlyphAtIndex: glyphIndex + 1];
kerning = p2.x - p1.x;


*ascent = (float) Fix2X (asc);
}
if (ascent != 0)
*ascent = this->ascent;


if (descent != 0)
{
ATSUTextMeasurement desc;
ByteCount actualSize;
if (descent != 0)
*descent = fabsf ([font descender]);


ATSUGetLineControl (layout,
0,
kATSULineDescentTag,
sizeof (ATSUTextMeasurement),
&desc,
&actualSize);

*descent = (float) Fix2X (desc);
}

if (path != 0)
{
OSStatus callbackResult;

ok = (ATSUGlyphGetCubicPaths (style,
layoutRecords[1].glyphID,
moveToProc,
lineToProc,
curveToProc,
closePathProc,
(void*) path,
&callbackResult) == noErr);

if (numDeltaYs > 0 && ok)
{
const float dy = (float) Fix2X (deltaYs[1]);
if (path != 0)
{
NSBezierPath* bez = [NSBezierPath bezierPath];
[bez moveToPoint: NSMakePoint (0, 0)];
[bez appendBezierPathWithGlyph: [layoutManager glyphAtIndex: glyphIndex]
inFont: font];


path->applyTransform (AffineTransform::translation (0.0f, dy));
}
}
else
for (int i = 0; i < [bez elementCount]; ++i)
{
NSPoint p[3];
switch ([bez elementAtIndex: i associatedPoints: p])
{ {
ok = true;
case NSMoveToBezierPathElement:
path->startNewSubPath (p[0].x, -p[0].y);
break;
case NSLineToBezierPathElement:
path->lineTo (p[0].x, -p[0].y);
break;
case NSCurveToBezierPathElement:
path->cubicTo (p[0].x, -p[0].y, p[1].x, -p[1].y, p[2].x, -p[2].y);
break;
case NSClosePathBezierPathElement:
path->closeSubPath();
break;
default:
jassertfalse
break;
} }
} }

if (deltaYs != 0)
ATSUDirectReleaseLayoutDataArrayPtr (0, kATSUDirectDataBaselineDeltaFixedArray,
(void**) &deltaYs);

if (layoutRecords != 0)
ATSUDirectReleaseLayoutDataArrayPtr (0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void**) &layoutRecords);

ATSUDisposeTextLayout (layout);
} }


return kerning;
}

float getAscent()
{
return ascent;
}

float getTotalHeight()
{
return totalSize;
return kerning != 0;
} }


juce_wchar getDefaultChar() juce_wchar getDefaultChar()
@@ -269559,35 +269412,35 @@ public:
} }
}; };


class ATSFontHelperCache : public Timer,
public DeletedAtShutdown
class FontHelperCache : public Timer,
public DeletedAtShutdown
{ {
VoidArray cache; VoidArray cache;


public: public:
ATSFontHelperCache()
FontHelperCache()
{ {
} }


~ATSFontHelperCache()
~FontHelperCache()
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);
delete f; delete f;
} }


clearSingletonInstance(); clearSingletonInstance();
} }


ATSFontHelper* getFont (const String& name,
const bool bold,
const bool italic,
const float size = 1024)
FontHelper* getFont (const String& name,
const bool bold,
const bool italic,
const float size = 1024)
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);


if (f->name == name if (f->name == name
&& f->isBold == bold && f->isBold == bold
@@ -269599,16 +269452,16 @@ public:
} }
} }


ATSFontHelper* const f = new ATSFontHelper (name, bold, italic, size);
FontHelper* const f = new FontHelper (name, bold, italic, size);
cache.add (f); cache.add (f);
return f; return f;
} }


void releaseFont (ATSFontHelper* f)
void releaseFont (FontHelper* f)
{ {
for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f2 = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f2 = (FontHelper*) cache.getUnchecked(i);


if (f == f2) if (f == f2)
{ {
@@ -269628,7 +269481,7 @@ public:


for (int i = cache.size(); --i >= 0;) for (int i = cache.size(); --i >= 0;)
{ {
ATSFontHelper* const f = (ATSFontHelper*) cache.getUnchecked(i);
FontHelper* const f = (FontHelper*) cache.getUnchecked(i);


if (f->refCount == 0) if (f->refCount == 0)
{ {
@@ -269641,10 +269494,10 @@ public:
delete this; delete this;
} }


juce_DeclareSingleton_SingleThreaded_Minimal (ATSFontHelperCache)
juce_DeclareSingleton_SingleThreaded_Minimal (FontHelperCache)
}; };


juce_ImplementSingleton_SingleThreaded (ATSFontHelperCache)
juce_ImplementSingleton_SingleThreaded (FontHelperCache)


void Typeface::initialiseTypefaceCharacteristics (const String& fontName, void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
bool bold, bool bold,
@@ -269654,11 +269507,11 @@ void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
// This method is only safe to be called from the normal UI thread.. // This method is only safe to be called from the normal UI thread..
jassert (MessageManager::getInstance()->isThisTheMessageThread()); jassert (MessageManager::getInstance()->isThisTheMessageThread());


ATSFontHelper* const helper = ATSFontHelperCache::getInstance()
->getFont (fontName, bold, italic);
FontHelper* const helper = FontHelperCache::getInstance()
->getFont (fontName, bold, italic);


clear(); clear();
setAscent (helper->getAscent() / helper->getTotalHeight());
setAscent (helper->ascent / helper->totalSize);
setName (fontName); setName (fontName);
setDefaultCharacter (helper->getDefaultChar()); setDefaultCharacter (helper->getDefaultChar());
setBold (bold); setBold (bold);
@@ -269670,7 +269523,7 @@ void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
jassertfalse jassertfalse
} }


ATSFontHelperCache::getInstance()->releaseFont (helper);
FontHelperCache::getInstance()->releaseFont (helper);
} }


bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw() bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
@@ -269678,8 +269531,8 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
// This method is only safe to be called from the normal UI thread.. // This method is only safe to be called from the normal UI thread..
jassert (MessageManager::getInstance()->isThisTheMessageThread()); jassert (MessageManager::getInstance()->isThisTheMessageThread());


ATSFontHelper* const helper = ATSFontHelperCache::getInstance()
->getFont (getName(), isBold(), isItalic());
FontHelper* const helper = FontHelperCache::getInstance()
->getFont (getName(), isBold(), isItalic());


Path path; Path path;
float width; float width;
@@ -269687,10 +269540,10 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()


if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0)) if (helper->getPathAndKerning (character, T('I'), &path, width, 0, 0))
{ {
path.applyTransform (AffineTransform::scale (1.0f / helper->getTotalHeight(),
1.0f / helper->getTotalHeight()));
path.applyTransform (AffineTransform::scale (1.0f / helper->totalSize,
1.0f / helper->totalSize));


addGlyph (character, path, width / helper->getTotalHeight());
addGlyph (character, path, width / helper->totalSize);


for (int i = 0; i < glyphs.size(); ++i) for (int i = 0; i < glyphs.size(); ++i)
{ {
@@ -269699,7 +269552,7 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
float kerning; float kerning;
if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0)) if (helper->getPathAndKerning (character, g->getCharacter(), 0, kerning, 0, 0))
{ {
kerning = (kerning - width) / helper->getTotalHeight();
kerning = (kerning - width) / helper->totalSize;


if (kerning != 0) if (kerning != 0)
addKerningPair (character, g->getCharacter(), kerning); addKerningPair (character, g->getCharacter(), kerning);
@@ -269707,7 +269560,7 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()


if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0)) if (helper->getPathAndKerning (g->getCharacter(), character, 0, kerning, 0, 0))
{ {
kerning = kerning / helper->getTotalHeight() - g->width;
kerning = kerning / helper->totalSize - g->width;


if (kerning != 0) if (kerning != 0)
addKerningPair (g->getCharacter(), character, kerning); addKerningPair (g->getCharacter(), character, kerning);
@@ -269717,68 +269570,19 @@ bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
foundOne = true; foundOne = true;
} }


ATSFontHelperCache::getInstance()->releaseFont (helper);
FontHelperCache::getInstance()->releaseFont (helper);
return foundOne; return foundOne;
} }


const StringArray Font::findAllTypefaceNames() throw() const StringArray Font::findAllTypefaceNames() throw()
{ {
StringArray names; StringArray names;
ATSFontIterator iter;

if (ATSFontIteratorCreate (kATSFontContextGlobal,
0,
0,
kATSOptionFlagsRestrictedScope,
&iter) == noErr)
{
ATSFontRef font;

while (ATSFontIteratorNext (iter, &font) == noErr)
{
CFStringRef name;

if (ATSFontGetName (font,
kATSOptionFlagsDefault,
&name) == noErr)
{
const String nm (PlatformUtilities::cfStringToJuceString (name));

if (nm.isNotEmpty())
names.add (nm);


CFRelease (name);
}
}

ATSFontIteratorRelease (&iter);
}

// Use some totuous logic to eliminate bold/italic versions of fonts that we've already got
// a plain version of. This is only necessary because of Carbon's total lack of support
// for dealing with font families...
for (int j = names.size(); --j >= 0;)
{
const char* const endings[] = { " bold", " italic", " bold italic", " bolditalic",
" oblque", " bold oblique", " boldoblique" };

for (int i = 0; i < numElementsInArray (endings); ++i)
{
const String ending (endings[i]);

if (names[j].endsWithIgnoreCase (ending))
{
const String root (names[j].dropLastCharacters (ending.length()).trimEnd());
const ScopedAutoReleasePool pool;
NSArray* fonts = [[NSFontManager sharedFontManager] availableFontFamilies];


if (names.contains (root)
|| names.contains (root + T(" plain"), true))
{
names.remove (j);
break;
}
}
}
}
for (int i = 0; i < [fonts count]; ++i)
names.add (nsStringToJuce ((NSString*) [fonts objectAtIndex: i]));


names.sort (true); names.sort (true);
return names; return names;


Loading…
Cancel
Save