Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGTextMacBackend.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright(C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 
00040 #ifdef _MSC_VER
00041 # pragma warning (disable: 4786)
00042 #endif
00043 
00044 #include "OSGTextMacBackend.h"
00045 #include <OSGBaseTypes.h>
00046 
00047 
00048 #ifdef __APPLE__
00049 
00050 
00051 #include "OSGTextPixmapFace.h"
00052 #include "OSGTextPixmapGlyph.h"
00053 #include "OSGTextVectorFace.h"
00054 #include "OSGTextVectorGlyph.h"
00055 #include "OSGTextTXFFace.h"
00056 #include "OSGTextTXFGlyph.h"
00057 #include "OSGTextLayoutParam.h"
00058 #include "OSGTextLayoutResult.h"
00059 
00060 #include <iostream>
00061 #include <algorithm>
00062 #include <set>
00063 
00064 #include <ApplicationServices/ApplicationServices.h>
00065 
00066 
00067 using namespace std;
00068 
00069 
00070 OSG_BEGIN_NAMESPACE
00071 
00072 
00073 //----------------------------------------------------------------------
00074 // MacOS X specific implementation of the TextVectorFace class
00075 // Author: pdaehne
00076 //----------------------------------------------------------------------
00077 class TextMacVectorFace: public TextVectorFace
00078 {
00079 public:
00080 
00081     // Constructor
00082     TextMacVectorFace(ATSUStyle horiFontStyle);
00083 
00084     // Destructor
00085     virtual ~TextMacVectorFace();
00086 
00087     // Lays out one line of text
00088     virtual void layout(const wstring &text, const TextLayoutParam &param,
00089                         TextLayoutResult &layoutResult);
00090 
00091 protected:
00092 
00093     // Creates a new Glyph object
00094     virtual auto_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
00095 
00096 private:
00097 
00098     // The style objects that define the font
00099     ATSUStyle _horiFontStyle;
00100     ATSUStyle _vertFontStyle;
00101 
00102     // The layout objects that handle the text layout
00103     ATSUTextLayout _horiTextLayout;
00104     ATSUTextLayout _vertTextLayout;
00105 };
00106 
00107 
00108 //----------------------------------------------------------------------
00109 // MacOS X specific implementation of the TextVectorGlyph class
00110 // Author: pdaehne
00111 //----------------------------------------------------------------------
00112 class TextMacVectorGlyph: public TextVectorGlyph
00113 {
00114 public:
00115 
00116     // Constructor
00117     TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle);
00118 
00119     // Destructor
00120     virtual ~TextMacVectorGlyph();
00121 };
00122 
00123 
00124 //----------------------------------------------------------------------
00125 // MacOS X specific implementation of the TextPixmapFace class
00126 // Author: pdaehne
00127 //----------------------------------------------------------------------
00128 class TextMacPixmapFace: public TextPixmapFace
00129 {
00130 public:
00131 
00132     // Constructor
00133     TextMacPixmapFace(ATSUStyle horiFontStyle);
00134 
00135     // Destructor
00136     virtual ~TextMacPixmapFace();
00137 
00138     // Lays out one line of text
00139     virtual void layout(const wstring &text, const TextLayoutParam &param,
00140                         TextLayoutResult &layoutResult);
00141 
00142 protected:
00143 
00144     // Creates a new Glyph object
00145     virtual auto_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
00146 
00147 private:
00148 
00149     const TextPixmapGlyph &getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal);
00150 
00151     // The style objects that define the font
00152     ATSUStyle _horiFontStyle;
00153     ATSUStyle _vertFontStyle;
00154 
00155     // The layout objects that handle the text layout
00156     ATSUTextLayout _horiTextLayout;
00157     ATSUTextLayout _vertTextLayout;
00158 };
00159 
00160 
00161 //----------------------------------------------------------------------
00162 // MacOS X specific implementation of the TextPixmapGlyph class
00163 // Author: pdaehne
00164 //----------------------------------------------------------------------
00165 class TextMacPixmapGlyph: public TextPixmapGlyph
00166 {
00167 public:
00168 
00169     // Constructor
00170     TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
00171         Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
00172         Real32 vertAdvance, Int32 vertBearingX, Int32 vertBearingY,
00173         UInt8 *pixmap);
00174 
00175     // Destructor
00176     virtual ~TextMacPixmapGlyph();
00177 };
00178 
00179 
00180 //----------------------------------------------------------------------
00181 // MacOS X specific implementation of the TextTXFFace class
00182 // Author: pdaehne
00183 //----------------------------------------------------------------------
00184 class TextMacTXFFace: public TextTXFFace
00185 {
00186 public:
00187 
00188     // Constructor
00189     TextMacTXFFace(ATSUStyle horiFontStyle, const TextTXFParam &param);
00190 
00191     // Destructor
00192     virtual ~TextMacTXFFace();
00193 
00194 private:
00195 
00196     void createGlyphs(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle,
00197                       ATSUTextLayout horiTextLayout, ATSUTextLayout vertTextLayout,
00198                       const TextTXFParam &param);
00199 };
00200 
00201 
00202 //----------------------------------------------------------------------
00203 // MacOS X specific implementation of the TextTXFGlyph class
00204 // Author: pdaehne
00205 //----------------------------------------------------------------------
00206 class TextMacTXFGlyph: public TextTXFGlyph
00207 {
00208 public:
00209 
00210     // Constructor
00211     TextMacTXFGlyph(Index glyphIndex, Real32 scale, const ATSGlyphScreenMetrics &horiMetrics, const ATSGlyphScreenMetrics &vertMetrics);
00212 
00213     // Destructor
00214     virtual ~TextMacTXFGlyph();
00215 };
00216 
00217 
00218 //----------------------------------------------------------------------
00219 // Constructor
00220 // Author: pdaehne
00221 //----------------------------------------------------------------------
00222 TextMacBackend::TextMacBackend(): TextBackend() {}
00223 
00224 
00225 //----------------------------------------------------------------------
00226 // Destructor
00227 // Author: pdaehne
00228 //----------------------------------------------------------------------
00229 TextMacBackend::~TextMacBackend() {}
00230 
00231 
00232 //----------------------------------------------------------------------
00233 // Returns the family name of a font
00234 // Author: pdaehne
00235 //----------------------------------------------------------------------
00236 static string getFamilyName(ATSUFontID fontID)
00237 {
00238     ItemCount fontNameIndex;
00239     OSStatus result = ATSUFindFontName(fontID, kFontFamilyName, kFontNoPlatformCode,
00240                                        kFontNoScriptCode, kFontNoLanguageCode,
00241                                        0, 0, 0, &fontNameIndex);
00242     if (result != noErr)
00243         return string();
00244     ByteCount actualNameLength;
00245     result = ATSUGetIndFontName(fontID, fontNameIndex, 0, 0, &actualNameLength,
00246                                 0, 0, 0, 0);
00247     if ((result != noErr) || (actualNameLength == 0))
00248         return string();
00249     vector<char> name;
00250     name.resize(actualNameLength);
00251     FontPlatformCode fontNamePlatform;
00252     result = ATSUGetIndFontName(fontID, fontNameIndex, actualNameLength, &(name.front()), 0,
00253                                 0, &fontNamePlatform, 0, 0);
00254     if ((result != noErr) || (actualNameLength == 0))
00255         return string();
00256     CFStringRef str = 0;
00257     switch (fontNamePlatform)
00258     {
00259         case kFontUnicodePlatform:
00260         case kFontMicrosoftPlatform: // ???
00261             str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
00262                                           actualNameLength, kCFStringEncodingUnicode, false);
00263             break;
00264         case kFontMacintoshPlatform:
00265             str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
00266                                           actualNameLength, kCFStringEncodingMacRoman, false);
00267             break;
00268         default:
00269             return string();
00270     }
00271     if (str == 0)
00272         return string();
00273     CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, ' ');
00274     CFRelease(str);
00275     if (data == 0)
00276         return string();
00277     string familyName(reinterpret_cast<const char*>(CFDataGetBytePtr(data)),
00278                       static_cast<string::size_type>(CFDataGetLength(data)));
00279     CFRelease(data);
00280     return familyName;
00281 }
00282 
00283 
00284 //----------------------------------------------------------------------
00285 // Tries to find a font
00286 // Author: pdaehne
00287 //----------------------------------------------------------------------
00288 static ATSUStyle findFont(const string &family, TextFace::Style style, UInt32 size)
00289 {
00290     // Handle generic family names
00291     string f;
00292     if (family == "SERIF")
00293         f = "Times New Roman";
00294     else if (family == "SANS")
00295         f = "Arial";
00296     else if (family == "TYPEWRITER")
00297         f = "Courier";
00298     else
00299         f = family;
00300 
00301     // Get the number of fonts installed
00302     ItemCount fontCount;
00303     OSStatus result = ATSUFontCount(&fontCount);
00304     if ((result != noErr) || (fontCount == 0))
00305         return 0;
00306 
00307     // Get the IDs of all fonts
00308     vector<ATSUFontID> fontIDs;
00309     fontIDs.resize(fontCount);
00310     result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
00311     if (result != noErr)
00312         return 0;
00313 
00314     // Try to find the font
00315     ItemCount i;
00316     for (i = 0; i < fontCount; ++i)
00317     {
00318         string familyName = getFamilyName(fontIDs[i]);
00319         if (familyName == f)
00320             break;
00321     }
00322     if (i >= fontCount)
00323         return 0;
00324     ATSUFontID fontID = fontIDs[i];
00325 
00326     FMFontFamily fontFamily;
00327     result = FMGetFontFamilyInstanceFromFont(fontID, &fontFamily, 0);
00328     if (result != noErr)
00329         return 0;
00330     FMFontStyle fStyle;
00331     switch (style)
00332     {
00333         default:
00334         case TextFace::STYLE_PLAIN:      fStyle = normal;        break;
00335         case TextFace::STYLE_BOLD:       fStyle = bold;          break;
00336         case TextFace::STYLE_ITALIC:     fStyle = italic;        break;
00337         case TextFace::STYLE_BOLDITALIC: fStyle = bold | italic; break;
00338     }
00339     result = FMGetFontFromFontFamilyInstance(fontFamily, fStyle, &fontID, 0);
00340     if ((result != noErr) || (fontID == kATSUInvalidFontID))
00341         return 0;
00342 
00343     // Create style object
00344     ATSUStyle fontStyle;
00345     result = ATSUCreateStyle(&fontStyle);
00346     if (result != noErr)
00347         return 0;
00348 
00349     // Set style attributes
00350     //Boolean bold = ((style == TextFace::STYLE_BOLD) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
00351     //Boolean italic = ((style == TextFace::STYLE_ITALIC) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
00352     Fixed fontSize = IntToFixed(size);
00353     ATSUAttributeTag attributeTags[] = { kATSUFontTag, /*kATSUQDBoldfaceTag, kATSUQDItalicTag,*/ kATSUSizeTag };
00354     ByteCount attributeSizes[] = { sizeof(fontID), /*sizeof(bold), sizeof(italic),*/ sizeof(fontSize) };
00355     ATSUAttributeValuePtr attributeValues[] = { &fontID, /*&bold, &italic,*/ &fontSize };
00356     result = ATSUSetAttributes(fontStyle, /*4*/2, attributeTags, attributeSizes, attributeValues);
00357     if (result != noErr)
00358     {
00359         ATSUDisposeStyle(fontStyle);
00360         return 0;
00361     }
00362 
00363     return fontStyle;
00364 }
00365 
00366 
00367 //----------------------------------------------------------------------
00368 // Creates a new vector face
00369 // Author: pdaehne
00370 //----------------------------------------------------------------------
00371 TextVectorFace *TextMacBackend::createVectorFace(const string &family, TextFace::Style style)
00372 {
00373     // Try to find the font
00374     ATSUStyle horiFontStyle = findFont(family, style, 1000);
00375     if (horiFontStyle == 0)
00376         return 0;
00377 
00378     // Switch off hinting
00379     ATSStyleRenderingOptions styleRenderingOptions = kATSStyleNoHinting;
00380     ATSUAttributeTag attributeTag = kATSUStyleRenderingOptionsTag;
00381     ByteCount attributeSize = sizeof(styleRenderingOptions);
00382     ATSUAttributeValuePtr attributeValue = &styleRenderingOptions;
00383     OSStatus result = ATSUSetAttributes(horiFontStyle, 1, &attributeTag, &attributeSize, &attributeValue);
00384     // We don't care for errors - this is not really an important attribute
00385 
00386     // Create and return the new face object
00387     return new TextMacVectorFace(horiFontStyle);
00388 }
00389 
00390 
00391 //----------------------------------------------------------------------
00392 // Creates a new pixmap face
00393 // Author: pdaehne
00394 //----------------------------------------------------------------------
00395 TextPixmapFace *TextMacBackend::createPixmapFace(const string &family, TextFace::Style style, UInt32 size)
00396 {
00397     // Try to find the font
00398     ATSUStyle horiFontStyle = findFont(family, style, size);
00399     if (horiFontStyle == 0)
00400         return 0;
00401 
00402     // Create and return the new face object
00403     return new TextMacPixmapFace(horiFontStyle);
00404 }
00405 
00406 
00407 //----------------------------------------------------------------------
00408 // Creates a new TXF face
00409 // Author: pdaehne
00410 //----------------------------------------------------------------------
00411 TextTXFFace *TextMacBackend::createTXFFace(const string &family,
00412                                            TextFace::Style style,
00413                                            const TextTXFParam &param)
00414 {
00415     // Try to find the font
00416     ATSUStyle horiFontStyle = findFont(family, style, param.size);
00417     if (horiFontStyle == 0)
00418         return 0;
00419 
00420     // Create and return the new face object
00421     return new TextMacTXFFace(horiFontStyle, param);
00422 }
00423 
00424 
00425 //----------------------------------------------------------------------
00426 // Returns the names of all font families available
00427 // Author: pdaehne
00428 //----------------------------------------------------------------------
00429 void TextMacBackend::getFontFamilies(vector<string> &families)
00430 {
00431     families.clear();
00432 
00433     // Get the number of fonts installed
00434     ItemCount fontCount;
00435     OSStatus result = ATSUFontCount(&fontCount);
00436     if ((result != noErr) || (fontCount == 0))
00437         return;
00438 
00439     // Get the IDs of all fonts
00440     vector<ATSUFontID> fontIDs;
00441     fontIDs.resize(fontCount);
00442     result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
00443     if (result != noErr)
00444         return;
00445 
00446     // Put all font families into the vector
00447     ItemCount i;
00448     set<string> familySet;
00449     for (i = 0; i < fontCount; ++i)
00450     {
00451         string familyName = getFamilyName(fontIDs[i]);
00452         if (familyName.empty() == false)
00453             familySet.insert(familyName);
00454     }
00455     families.assign(familySet.begin(), familySet.end());
00456 }
00457 
00458 
00459 //----------------------------------------------------------------------
00460 // Tries to get information about the face
00461 // Author: pdaehne
00462 //----------------------------------------------------------------------
00463 static void getFaceInfo(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle, string &family, TextFace::Style &style,
00464     Real32 &horiAscent, Real32 &horiDescent,
00465     Real32 &vertAscent, Real32 &vertDescent)
00466 {
00467     // Try to get the family name
00468     ATSUFontID fontID;
00469     OSStatus result = ATSUGetAttribute(horiFontStyle, kATSUFontTag, sizeof(fontID), &fontID, 0);
00470     if (((result == noErr) || (result == kATSUNotSetErr)) && (fontID != kATSUInvalidFontID))
00471         family = getFamilyName(fontID);
00472     else
00473         family.erase();
00474 
00475     // Try to get style
00476     Boolean bold;
00477     result = ATSUGetAttribute(horiFontStyle, kATSUQDBoldfaceTag, sizeof(bold), &bold, 0);
00478     if ((result != noErr) && (result != kATSUNotSetErr))
00479         bold = false;
00480     Boolean italic;
00481     result = ATSUGetAttribute(horiFontStyle, kATSUQDItalicTag, sizeof(italic), &italic, 0);
00482     if ((result != noErr) && (result != kATSUNotSetErr))
00483         italic = false;
00484     style = (bold == TRUE) ?
00485         (italic == TRUE ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD) :
00486         (italic == TRUE ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN);
00487 
00488     // Try to get ascent
00489     ATSUTextMeasurement measurement;
00490     result = ATSUGetAttribute(horiFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
00491     horiAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
00492     result = ATSUGetAttribute(vertFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
00493     vertAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
00494 
00495     // Try to get descent
00496     result = ATSUGetAttribute(horiFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
00497     horiDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
00498     result = ATSUGetAttribute(vertFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
00499     vertDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
00500 }
00501 
00502 
00503 //----------------------------------------------------------------------
00504 // Creates all ATSU objects needed by a face
00505 // Author: pdaehne
00506 //----------------------------------------------------------------------
00507 static void createATSUObjects(ATSUStyle horiFontStyle, ATSUStyle &vertFontStyle, ATSUTextLayout &horiTextLayout, ATSUTextLayout &vertTextLayout)
00508 {
00509     // Create vertical style object
00510     OSStatus result = ATSUCreateAndCopyStyle(horiFontStyle, &vertFontStyle);
00511     if (result != noErr)
00512         vertFontStyle = 0;
00513     else
00514     {
00515         ATSUVerticalCharacterType verticalCharacterType = kATSUStronglyVertical;
00516         ATSUAttributeTag attributeTags[] = { kATSUVerticalCharacterTag };
00517         ByteCount attributeSizes[] = { sizeof(verticalCharacterType) };
00518         ATSUAttributeValuePtr attributeValues[] = { &verticalCharacterType };
00519         result = ATSUSetAttributes(vertFontStyle, 1, attributeTags, attributeSizes, attributeValues);
00520     }
00521 
00522     // Create the layout objects
00523     result = ATSUCreateTextLayout(&horiTextLayout);
00524     if (result != noErr)
00525         horiTextLayout = 0;
00526     result = ATSUCreateAndCopyTextLayout(horiTextLayout, &vertTextLayout);
00527     if (result != noErr)
00528         vertTextLayout = 0;
00529     else
00530     {
00531         Fixed lineRotation = IntToFixed(-90);
00532         ATSUAttributeTag layoutAttributeTags[] = { kATSULineRotationTag };
00533         ByteCount layoutAttributeSizes[] = { sizeof(lineRotation) };
00534         ATSUAttributeValuePtr layoutAttributeValues[] = { &lineRotation };
00535         result = ATSUSetLayoutControls(vertTextLayout, 1, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
00536     }
00537 }
00538 
00539 
00540 //----------------------------------------------------------------------
00541 // Constructor
00542 // Author: pdaehne
00543 //----------------------------------------------------------------------
00544 TextMacVectorFace::TextMacVectorFace(ATSUStyle horiFontStyle)
00545 : TextVectorFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
00546 {
00547     // Create all ATSU objects
00548     createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
00549 
00550     // Try to get information about the face
00551     getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
00552         _horiAscent, _horiDescent, _vertAscent, _vertDescent);
00553 
00554     // Determine the scale factor
00555     _scale = 1.f / (_horiAscent - _horiDescent);
00556 
00557     // Determine ascent
00558     _horiAscent *= _scale;
00559     _vertAscent = -0.5f;
00560 
00561     // Determine descent
00562     _horiDescent *= _scale;
00563     _vertDescent = 0.5f;
00564 }
00565 
00566 
00567 //----------------------------------------------------------------------
00568 // Destructor
00569 // Author: pdaehne
00570 //----------------------------------------------------------------------
00571 TextMacVectorFace::~TextMacVectorFace()
00572 {
00573     // Dispose the layout objects
00574     ATSUDisposeTextLayout(_horiTextLayout);
00575     ATSUDisposeTextLayout(_vertTextLayout);
00576 
00577     // Dispose style objects
00578     ATSUDisposeStyle(_horiFontStyle);
00579     ATSUDisposeStyle(_vertFontStyle);
00580 }
00581 
00582 
00583 //----------------------------------------------------------------------
00584 // Converts a unicode string to utf16
00585 // RFC2781: UTF-16, an encoding of ISO 10646
00586 // Author: pdaehne
00587 //----------------------------------------------------------------------
00588 static void convertUnicodeToUTF16(const wstring &text, vector<UniChar> &utf16Text)
00589 {
00590     UniCharCount i, textTotalLength = text.length();
00591     utf16Text.clear();
00592     utf16Text.reserve(textTotalLength);
00593     for (i = 0; i < textTotalLength; ++i)
00594     {
00595         wchar_t unicode = text[i];
00596         if (unicode < 0x10000)
00597             utf16Text.push_back(unicode);
00598         else if (unicode < 0x110000)
00599         {
00600             unsigned long u = unicode - 0x10000;
00601             utf16Text.push_back(0xd800 | (u >> 10));
00602             utf16Text.push_back(0xdc00 | (u & 0x3ff));
00603         }
00604     }
00605 }
00606 
00607 
00608 //----------------------------------------------------------------------
00609 // Lays out one line of text
00610 // Author: pdaehne
00611 //----------------------------------------------------------------------
00612 void TextMacVectorFace::layout(const wstring &text, const TextLayoutParam &param,
00613                                TextLayoutResult &layoutResult)
00614 {
00615     // Initialize return values
00616     layoutResult.clear();
00617     if (param.horizontal == true)
00618         layoutResult.textBounds[1] = _horiAscent - _horiDescent;
00619     else
00620         layoutResult.textBounds[0] = _vertDescent - _vertAscent;
00621     layoutResult.lineBounds.push_back(layoutResult.textBounds);
00622 
00623     // Convert the unicode string to utf16
00624     vector<UniChar> utf16Text;
00625     convertUnicodeToUTF16(text, utf16Text);
00626     if (utf16Text.empty() == true)
00627         return;
00628 
00629     // Check whether we have to use the horizontal or vertical ATSUI objects
00630     ATSUStyle fontStyle;
00631     ATSUTextLayout textLayout;
00632     if (param.horizontal == true)
00633     {
00634         fontStyle = _horiFontStyle;
00635         textLayout = _horiTextLayout;
00636     }
00637     else
00638     {
00639         fontStyle = _vertFontStyle;
00640         textLayout = _vertTextLayout;
00641     }
00642 
00643     // Set the length
00644     Real32 length = param.getLength(0);
00645     Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
00646     ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length / _scale);
00647     ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
00648     ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
00649     ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
00650     ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
00651 
00652     // Set the text
00653     OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
00654     if (result != noErr)
00655         return;
00656 
00657     // Set the style object
00658     result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
00659     if (result != noErr)
00660         return;
00661 
00662     // Get the layout records
00663     ATSLayoutRecord *layoutRecords;
00664     ItemCount numRecords;
00665     result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
00666         kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
00667     if (result != noErr)
00668         return;
00669     Fixed *deltaYs;
00670     ItemCount numDeltaYs;
00671     result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
00672         kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
00673     if (result != noErr)
00674         deltaYs = 0;
00675 
00676     // Calculate the positions of the glyphs
00677     layoutResult.indices.reserve(numRecords);
00678     layoutResult.positions.reserve(numRecords);
00679     ItemCount j;
00680     Vec2f currPos;
00681     for (j = 0; j < numRecords; ++j)
00682     {
00683         ATSGlyphRef glyphID = layoutRecords[j].glyphID;
00684         currPos[0] = FixedToFloat(layoutRecords[j].realPos) * _scale;
00685         currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) * _scale: 0.f;
00686         const TextVectorGlyph &glyph = getVectorGlyph(glyphID);
00687         if (param.horizontal == true)
00688         {
00689             currPos[0] += glyph.getHoriBearingX();
00690             currPos[1] += glyph.getHoriBearingY();
00691         }
00692         else
00693         {
00694             float h = currPos.x();
00695             currPos[0] = currPos.y() + glyph.getVertBearingX();
00696             currPos[1] = -h + glyph.getVertBearingY();
00697         }
00698         if (glyphID != kATSDeletedGlyphcode)
00699         {
00700             layoutResult.indices.push_back(glyphID);
00701             layoutResult.positions.push_back(currPos);
00702         }
00703     }
00704 
00705     // Cleanup
00706     if (deltaYs != 0)
00707         ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
00708     ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
00709 
00710     // Adjust the origin depending on the major and the minor alignment
00711     adjustLineOrigin(param, currPos, layoutResult);
00712 
00713     // Determine text bounds / line bounds
00714     if (param.horizontal == true)
00715         layoutResult.textBounds[0] = osgabs(currPos.x());
00716     else
00717         layoutResult.textBounds[1] = osgabs(currPos.y());
00718     assert(layoutResult.lineBounds.empty() == false);
00719     layoutResult.lineBounds.front() = layoutResult.textBounds;
00720 }
00721 
00722 
00723 //----------------------------------------------------------------------
00724 // Helper object used by the decompose callback functions
00725 // Author: pdaehne
00726 //----------------------------------------------------------------------
00727 typedef struct UserData
00728 {
00729     Real32 scale;
00730     Vec2f offset;
00731     TextVectorGlyph::Outline &outline;
00732     inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
00733     : scale(s), offset(off), outline(o)
00734     {}
00735 }
00736 UserData;
00737 
00738 
00739 //----------------------------------------------------------------------
00740 // callback function that starts a new contour
00741 // Author: pdaehne
00742 //----------------------------------------------------------------------
00743 static OSStatus quadraticNewPathCallback(void *callBackDataPtr)
00744 {
00745     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00746 
00747     // We start a new contour
00748     userData->outline.push_back(TextVectorGlyph::Contour());
00749 
00750     // Continue
00751     return noErr;
00752 }
00753 
00754 
00755 //----------------------------------------------------------------------
00756 // callback function that adds a line to the contour
00757 // Author: pdaehne
00758 //----------------------------------------------------------------------
00759 static OSStatus quadraticLineCallback(const Float32Point *pt1, const Float32Point *pt2, void *callBackDataPtr)
00760 {
00761     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00762 
00763     // When this is the first segment, we have to put the first point into the contour
00764     if (userData->outline.back().empty() == true)
00765     {
00766         Vec2f p(pt1->x, -pt1->y);
00767         p *= userData->scale;
00768         p -= userData->offset;
00769         userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00770     }
00771 
00772     // We have a point on the line
00773     Vec2f p(pt2->x, -pt2->y);
00774     p *= userData->scale;
00775     p -= userData->offset;
00776     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00777 
00778     // Continue
00779     return noErr;
00780 }
00781 
00782 
00783 //----------------------------------------------------------------------
00784 // callback function that adds a quadratic Bezier spline to the contour
00785 // Author: pdaehne
00786 //----------------------------------------------------------------------
00787 static OSStatus quadraticCurveCallback(const Float32Point *pt1, const Float32Point *controlPt, const Float32Point *pt2, void *callBackDataPtr)
00788 {
00789     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00790 
00791     // When this is the first segment, we have to put the first point into the contour
00792     if (userData->outline.back().empty() == true)
00793     {
00794         Vec2f p(pt1->x, -pt1->y);
00795         p *= userData->scale;
00796         p -= userData->offset;
00797         userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00798     }
00799 
00800     // We have a control point and a point on the line
00801     Vec2f p(controlPt->x, -controlPt->y);
00802     p *= userData->scale;
00803     p -= userData->offset;
00804     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
00805     p.setValues(pt2->x, -pt2->y);
00806     p *= userData->scale;
00807     p -= userData->offset;
00808     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00809 
00810     // Continue
00811     return noErr;
00812 }
00813 
00814 
00815 //----------------------------------------------------------------------
00816 // callback function that closes a contour
00817 // Author: pdaehne
00818 //----------------------------------------------------------------------
00819 OSStatus quadraticClosePathCallback(void *callBackDataPtr)
00820 {
00821     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00822 
00823     // Check if the contour is valid, i.e. if it has more than three points.
00824     // When not, we simply delete the contour.
00825     if (userData->outline.back().size() < 3)
00826         userData->outline.erase(userData->outline.end() - 1);
00827 
00828     // Continue
00829     return noErr;
00830 }
00831 
00832 
00833 //----------------------------------------------------------------------
00834 // callback function that starts a new contour
00835 // Author: pdaehne
00836 //----------------------------------------------------------------------
00837 static OSStatus cubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
00838 {
00839     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00840 
00841     // We start a new contour
00842     userData->outline.push_back(TextVectorGlyph::Contour());
00843 
00844     // We have a point on the line
00845     Vec2f p(pt->x, -pt->y);
00846     p *= userData->scale;
00847     p -= userData->offset;
00848     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00849 
00850     // Continue
00851     return noErr;
00852 }
00853 
00854 
00855 //----------------------------------------------------------------------
00856 // callback function that adds a line to the contour
00857 // Author: pdaehne
00858 //----------------------------------------------------------------------
00859 static OSStatus cubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
00860 {
00861     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00862 
00863     // We have a point on the line
00864     Vec2f p(pt->x, -pt->y);
00865     p *= userData->scale;
00866     p -= userData->offset;
00867     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00868 
00869     // Continue
00870     return noErr;
00871 }
00872 
00873 
00874 //----------------------------------------------------------------------
00875 // callback function that adds a cubic Bezier spline to the contour
00876 // Author: pdaehne
00877 //----------------------------------------------------------------------
00878 static OSStatus cubicCurveToCallback(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *callBackDataPtr)
00879 {
00880     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00881 
00882     // We have two control points and a point on the line
00883     Vec2f p(pt1->x, -pt1->y);
00884     p *= userData->scale;
00885     p -= userData->offset;
00886     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
00887     p.setValues(pt2->x, -pt2->y);
00888     p *= userData->scale;
00889     p -= userData->offset;
00890     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
00891     p.setValues(pt3->x, -pt3->y);
00892     p *= userData->scale;
00893     p -= userData->offset;
00894     userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00895 
00896     // Continue
00897     return noErr;
00898 }
00899 
00900 
00901 //----------------------------------------------------------------------
00902 // callback function that closes a contour
00903 // Author: pdaehne
00904 //----------------------------------------------------------------------
00905 static OSStatus cubicClosePathCallback(void *callBackDataPtr)
00906 {
00907     UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
00908 
00909     // Check if the contour is valid, i.e. if it has more than two points.
00910     // When not, we simply delete the contour.
00911     if (userData->outline.back().size() < 3)
00912         userData->outline.erase(userData->outline.end() - 1);
00913 
00914     // Continue
00915     return noErr;
00916 }
00917 
00918 
00919 //----------------------------------------------------------------------
00920 // Creates a new Glyph object
00921 // Author: pdaehne
00922 //----------------------------------------------------------------------
00923 auto_ptr<TextVectorGlyph> TextMacVectorFace::createGlyph(TextGlyph::Index glyphIndex)
00924 {
00925     // We cannot create glyphs for invalid glyph indices
00926     if (glyphIndex == TextGlyph::INVALID_INDEX)
00927         return auto_ptr<TextVectorGlyph>();
00928 
00929     // Create and return the new glyph object
00930     return auto_ptr<TextVectorGlyph>(new TextMacVectorGlyph(glyphIndex, _scale, _horiFontStyle, _vertFontStyle));
00931 }
00932 
00933 
00934 //----------------------------------------------------------------------
00935 // Constructor
00936 // Author: pdaehne
00937 //----------------------------------------------------------------------
00938 TextMacVectorGlyph::TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle)
00939 : TextVectorGlyph()
00940 {
00941     _glyphIndex = glyphIndex;
00942 
00943     // Determine horizontal glyph metrics
00944     GlyphID glyphID = _glyphIndex;
00945     ATSGlyphScreenMetrics glyphScreenMetrics;
00946     OSStatus result = ATSUGlyphGetScreenMetrics(horiFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
00947     if (result == noErr)
00948     {
00949         _width = glyphScreenMetrics.width * scale;
00950         _height = glyphScreenMetrics.height * scale;
00951         _horiAdvance = glyphScreenMetrics.deviceAdvance.x * scale;
00952         _horiBearingX = glyphScreenMetrics.topLeft.x * scale;
00953         _horiBearingY = glyphScreenMetrics.topLeft.y * scale;
00954     }
00955 
00956     // Determine vertical glyph metrics
00957     result = ATSUGlyphGetScreenMetrics(vertFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
00958     if (result == noErr)
00959     {
00960         _width = glyphScreenMetrics.width * scale;
00961         _height = glyphScreenMetrics.height * scale;
00962         _vertAdvance = glyphScreenMetrics.deviceAdvance.y * scale;
00963         _vertBearingX = glyphScreenMetrics.topLeft.x * scale;
00964         _vertBearingY = glyphScreenMetrics.topLeft.y * scale;
00965     }
00966 
00967     // Get the outlines
00968     ATSCurveType curveType;
00969     result = ATSUGetNativeCurveType(horiFontStyle, &curveType);
00970     if (result != noErr)
00971         return;
00972     if (curveType == kATSQuadCurveType)
00973     {
00974         // This is quite ugly, we should do this only once for all glyphs.
00975         // But on MacOS X, this should be a NOP, anyway.
00976         ATSQuadraticNewPathUPP newPathProc = NewATSQuadraticNewPathUPP(&quadraticNewPathCallback);
00977         ATSQuadraticLineUPP lineProc = NewATSQuadraticLineUPP(&quadraticLineCallback);
00978         ATSQuadraticCurveUPP curveProc = NewATSQuadraticCurveUPP(&quadraticCurveCallback);
00979         ATSQuadraticClosePathUPP closePathProc = NewATSQuadraticClosePathUPP(&quadraticClosePathCallback);
00980         UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
00981         OSStatus callbackResult;
00982         result = ATSUGlyphGetQuadraticPaths(horiFontStyle, glyphID, newPathProc, lineProc, curveProc, closePathProc, &userData, &callbackResult);
00983         DisposeATSQuadraticClosePathUPP(closePathProc);
00984         DisposeATSQuadraticCurveUPP(curveProc);
00985         DisposeATSQuadraticLineUPP(lineProc);
00986         DisposeATSQuadraticNewPathUPP(newPathProc);
00987     }
00988     else if (curveType == kATSCubicCurveType)
00989     {
00990         // This is quite ugly, we should do this only once for all glyphs.
00991         // But on MacOS X, this should be a NOP, anyway.
00992         ATSCubicMoveToUPP moveToProc = NewATSCubicMoveToUPP(&cubicMoveToCallback);
00993         ATSCubicLineToUPP lineToProc = NewATSCubicLineToUPP(&cubicLineToCallback);
00994         ATSCubicCurveToUPP curveToProc = NewATSCubicCurveToUPP(&cubicCurveToCallback);
00995         ATSCubicClosePathUPP closePathProc = NewATSCubicClosePathUPP(&cubicClosePathCallback);
00996         UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
00997         OSStatus callbackResult;
00998         ATSUGlyphGetCubicPaths(horiFontStyle, glyphID, moveToProc, lineToProc, curveToProc, closePathProc, &userData, &callbackResult);
00999         DisposeATSCubicClosePathUPP(closePathProc);
01000         DisposeATSCubicCurveToUPP(curveToProc);
01001         DisposeATSCubicLineToUPP(lineToProc);
01002         DisposeATSCubicMoveToUPP(moveToProc);
01003     }
01004 }
01005 
01006 
01007 //----------------------------------------------------------------------
01008 // Destructor
01009 // Author: pdaehne
01010 //----------------------------------------------------------------------
01011 TextMacVectorGlyph::~TextMacVectorGlyph() {}
01012 
01013 
01014 //----------------------------------------------------------------------
01015 // Constructor
01016 // Author: pdaehne
01017 //----------------------------------------------------------------------
01018 TextMacPixmapFace::TextMacPixmapFace(ATSUStyle horiFontStyle)
01019 : TextPixmapFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
01020 {
01021     // Create all ATSU objects
01022     createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
01023 
01024     // Try to get information about the face
01025     getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
01026         _horiAscent, _horiDescent, _vertAscent, _vertDescent);
01027 
01028     // Determine the size
01029     Fixed size;
01030     OSStatus result = ATSUGetAttribute(_horiFontStyle, kATSUSizeTag, sizeof(size), &size, 0);
01031     _size = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToInt(size) : 0;
01032 }
01033 
01034 
01035 //----------------------------------------------------------------------
01036 // Destructor
01037 // Author: pdaehne
01038 //----------------------------------------------------------------------
01039 TextMacPixmapFace::~TextMacPixmapFace()
01040 {
01041     // Dispose the layout objects
01042     ATSUDisposeTextLayout(_horiTextLayout);
01043     ATSUDisposeTextLayout(_vertTextLayout);
01044 
01045     // Dispose style objects
01046     ATSUDisposeStyle(_horiFontStyle);
01047     ATSUDisposeStyle(_vertFontStyle);
01048 }
01049 
01050 
01051 //----------------------------------------------------------------------
01052 // Lays out one line of text
01053 // Author: pdaehne
01054 //----------------------------------------------------------------------
01055 void TextMacPixmapFace::layout(const wstring &text, const TextLayoutParam &param,
01056                                TextLayoutResult &layoutResult)
01057 {
01058     // Initialize return values
01059     layoutResult.clear();
01060     if (param.horizontal == true)
01061         layoutResult.textBounds[1] = _horiAscent - _horiDescent;
01062     else
01063         layoutResult.textBounds[0] = _vertDescent - _vertAscent;
01064     layoutResult.lineBounds.push_back(layoutResult.textBounds);
01065 
01066     // Convert the unicode string to utf16
01067     vector<UniChar> utf16Text;
01068     convertUnicodeToUTF16(text, utf16Text);
01069     if (utf16Text.empty() == true)
01070         return;
01071 
01072     // Check whether we have to use the horizontal or vertical ATSUI objects
01073     ATSUStyle fontStyle;
01074     ATSUTextLayout textLayout;
01075     if (param.horizontal == true)
01076     {
01077         fontStyle = _horiFontStyle;
01078         textLayout = _horiTextLayout;
01079     }
01080     else
01081     {
01082         fontStyle = _vertFontStyle;
01083         textLayout = _vertTextLayout;
01084     }
01085 
01086     // Set the length
01087     Real32 length = param.getLength(0);
01088     Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
01089     ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length);
01090     ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
01091     ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
01092     ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
01093     ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
01094 
01095     // Set the text
01096     OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
01097     if (result != noErr)
01098         return;
01099 
01100     // Set the style object
01101     result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
01102     if (result != noErr)
01103         return;
01104 
01105     // Get the layout records
01106     ATSLayoutRecord *layoutRecords;
01107     ItemCount numRecords;
01108     result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
01109         kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
01110     if (result != noErr)
01111         return;
01112     Fixed *deltaYs;
01113     ItemCount numDeltaYs;
01114     result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
01115         kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
01116     if (result != noErr)
01117         deltaYs = 0;
01118 
01119     // Calculate the positions of the glyphs
01120     layoutResult.indices.reserve(numRecords);
01121     layoutResult.positions.reserve(numRecords);
01122     ItemCount j;
01123     Vec2f currPos;
01124     for (j = 0; j < numRecords; ++j)
01125     {
01126         ATSGlyphRef glyphID = layoutRecords[j].glyphID;
01127         currPos[0] = FixedToFloat(layoutRecords[j].realPos);
01128         currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) : 0.f;
01129         const TextPixmapGlyph &glyph = getPixmapGlyph(layoutRecords[j], param.horizontal);
01130         if (param.horizontal == true)
01131         {
01132             currPos[0] += glyph.getHoriBearingX();
01133             currPos[1] += glyph.getHoriBearingY();
01134         }
01135         else
01136         {
01137             float h = currPos.x();
01138             currPos[0] = currPos.y() + glyph.getVertBearingX();
01139             currPos[1] = -h + glyph.getVertBearingY();
01140         }
01141         if (glyphID != kATSDeletedGlyphcode)
01142         {
01143             layoutResult.indices.push_back(glyphID);
01144             layoutResult.positions.push_back(currPos);
01145         }
01146     }
01147 
01148     // Cleanup
01149     if (deltaYs != 0)
01150         ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
01151     ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
01152 
01153     // Adjust the origin depending on the major and the minor alignment
01154     adjustLineOrigin(param, currPos, layoutResult);
01155 
01156     // Determine text bounds / line bounds
01157     if (param.horizontal == true)
01158         layoutResult.textBounds[0] = osgabs(currPos.x());
01159     else
01160         layoutResult.textBounds[1] = osgabs(currPos.y());
01161     assert(layoutResult.lineBounds.empty() == false);
01162     layoutResult.lineBounds.front() = layoutResult.textBounds;
01163 }
01164 
01165 
01166 //----------------------------------------------------------------------
01167 // Creates a new Glyph object
01168 // Author: pdaehne
01169 //----------------------------------------------------------------------
01170 auto_ptr<TextPixmapGlyph> TextMacPixmapFace::createGlyph(TextGlyph::Index glyphIndex)
01171 {
01172     return auto_ptr<TextPixmapGlyph>();
01173 }
01174 
01175 
01176 //----------------------------------------------------------------------
01177 // Renders a glyph into a memory buffer
01178 // Author: pdaehne
01179 //----------------------------------------------------------------------
01180 static void drawGlyph(ATSUTextLayout textLayout, const ATSLayoutRecord &layoutRecord,
01181                       ATSUTextMeasurement xPos, ATSUTextMeasurement yPos,
01182                       UInt32 width, UInt32 height, UInt8 *dst, UInt32 pitch)
01183 {
01184     // No need to draw invisible glyphs
01185     if ((width == 0) || (height == 0))
01186         return;
01187 
01188     // Create offscreen GWorld
01189     GWorldPtr offscreenGWorld;
01190     Rect boundsRect;
01191     SetRect(&boundsRect, 0, 0, width, height);
01192     QDErr qdResult = NewGWorld(&offscreenGWorld, 32, &boundsRect, 0, 0, 0);
01193     if (qdResult != noErr)
01194         return;
01195 
01196     // Get the pixel buffer of the offscreen GWorld
01197     if (LockPixels(GetGWorldPixMap(offscreenGWorld)) == FALSE)
01198     {
01199         DisposeGWorld(offscreenGWorld);
01200         return;
01201     }
01202     Ptr src = GetPixBaseAddr(GetGWorldPixMap(offscreenGWorld));
01203     if (src == 0)
01204     {
01205         UnlockPixels(GetGWorldPixMap(offscreenGWorld));
01206         DisposeGWorld(offscreenGWorld);
01207         return;
01208     }
01209 
01210     // Initialize and activate the offscreen GWorld
01211     CGrafPtr port;
01212     GDHandle gdh;
01213     GetGWorld(&port, &gdh);
01214     SetGWorld(offscreenGWorld, 0);
01215     RGBColor gBlackColour = { 0x0000, 0x0000, 0x0000 };
01216     RGBBackColor(&gBlackColour);
01217     EraseRect(&boundsRect);
01218     RGBColor gWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
01219     RGBForeColor(&gWhiteColour);
01220 
01221     // Draw the text
01222     UniCharArrayOffset charOffset = layoutRecord.originalOffset >> 1;
01223     UniCharCount charCount = (layoutRecord.flags & kATSGlyphInfoByteSizeMask) >> 1;
01224     OSStatus result = ATSUDrawText(textLayout, charOffset, charCount, xPos, yPos);
01225     if (result == noErr)
01226     {
01227         long bpl = GetPixRowBytes(GetGWorldPixMap(offscreenGWorld));
01228         src += bpl * (height - 1);
01229         Ptr src2;
01230         UInt32 x, y;
01231         for (y = 0; y < height; ++y)
01232         {
01233             src2 = src + 1;
01234             for (x = 0; x < width; ++x)
01235             {
01236                 *dst++ = *src2;
01237                 src2+= 4;
01238             }
01239             src -= bpl;
01240             dst += pitch;
01241         }
01242     }
01243 
01244     // Deactivate and destroy the offscreen GWorld
01245     SetGWorld(port, gdh);
01246     UnlockPixels(GetGWorldPixMap(offscreenGWorld));
01247     DisposeGWorld(offscreenGWorld);
01248 }
01249 
01250 
01251 //----------------------------------------------------------------------
01252 // Returns information about a glyph.
01253 // Author: pdaehne
01254 //----------------------------------------------------------------------
01255 const TextPixmapGlyph &TextMacPixmapFace::getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal)
01256 {
01257     ATSGlyphRef glyphID = layoutRecord.glyphID;
01258     if (glyphID == kATSDeletedGlyphcode)
01259         return _emptyGlyph;
01260 
01261     // Try to find the glyph in the map of glyphs
01262     GlyphMap::const_iterator it = _glyphMap.find(glyphID);
01263     if (it != _glyphMap.end())
01264     {
01265         assert(it->second != 0);
01266         return *(it->second);
01267     }
01268 
01269     // We did not find the glyph, so we have to create it
01270     ATSUTextMeasurement xPos = 0, yPos = 0;
01271 
01272     // Determine horizontal glyph metrics
01273     ATSGlyphScreenMetrics glyphScreenMetrics;
01274     OSStatus result = ATSUGlyphGetScreenMetrics(_horiFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
01275     if (result != noErr)
01276         return _emptyGlyph;
01277     Real32 horiAdvance = glyphScreenMetrics.deviceAdvance.x;
01278     UInt32 width = glyphScreenMetrics.width;
01279     UInt32 height = glyphScreenMetrics.height;
01280     Int32 horiBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
01281     Int32 horiBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
01282     if (horizontal == true)
01283     {
01284         xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x) - (layoutRecord.realPos & 0xffff0000);
01285         yPos = FloatToFixed(glyphScreenMetrics.topLeft.y);
01286     }
01287 
01288     // Determine vertical glyph metrics
01289     result = ATSUGlyphGetScreenMetrics(_vertFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
01290     if (result != noErr)
01291         return _emptyGlyph;
01292     Real32 vertAdvance = glyphScreenMetrics.deviceAdvance.y;
01293     Int32 vertBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
01294     Int32 vertBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
01295     if (horizontal == false)
01296     {
01297         xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x);
01298         yPos = FloatToFixed(glyphScreenMetrics.topLeft.y) - ((layoutRecord.realPos + fixed1) & 0xffff0000);
01299     }
01300 
01301     UInt8 *pixmap = 0;
01302     UInt32 size = width * height;
01303     if (size != 0)
01304     {
01305         // Create pixmap
01306         ATSUTextLayout textLayout = horizontal == true ? _horiTextLayout : _vertTextLayout;
01307         pixmap = new UInt8[size];
01308         drawGlyph(textLayout, layoutRecord, xPos, yPos, width, height, pixmap, 0);
01309     }
01310 
01311     auto_ptr<TextPixmapGlyph> glyph(new TextMacPixmapGlyph(glyphID, width, height, horiAdvance, horiBearingX, horiBearingY, vertAdvance, vertBearingX, vertBearingY, pixmap));
01312 
01313     // Put the glyph into the glyph cache
01314     _glyphMap.insert(GlyphMap::value_type(glyphID, glyph.get()));
01315 
01316     // Return the glyph
01317     return *(glyph.release());
01318 }
01319 
01320 
01321 //----------------------------------------------------------------------
01322 // Constructor
01323 // Author: pdaehne
01324 //----------------------------------------------------------------------
01325 TextMacPixmapGlyph::TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
01326     Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
01327     Real32 vertAdvance, Int32 vertBearingX, Int32 vertBearingY,
01328     UInt8 *pixmap)
01329 : TextPixmapGlyph()
01330 {
01331     _glyphIndex = glyphIndex;
01332     _width = _pitch = width;
01333     _height = height;
01334     _pixmap = pixmap;
01335 
01336     // Determine horizontal glyph metrics
01337     _horiAdvance = horiAdvance;
01338     _horiBearingX = horiBearingX;
01339     _horiBearingY = horiBearingY;
01340 
01341     // Determine vertical glyph metrics
01342     _vertAdvance = vertAdvance;
01343     _vertBearingX = vertBearingX;
01344     _vertBearingY = vertBearingY;
01345 }
01346 
01347 
01348 //----------------------------------------------------------------------
01349 // Destructor
01350 // Author: pdaehne
01351 //----------------------------------------------------------------------
01352 TextMacPixmapGlyph::~TextMacPixmapGlyph() {}
01353 
01354 
01355 //----------------------------------------------------------------------
01356 // Constructor
01357 // Author: pdaehne
01358 //----------------------------------------------------------------------
01359 TextMacTXFFace::TextMacTXFFace(ATSUStyle horiFontStyle, const TextTXFParam &param)
01360 : TextTXFFace()
01361 {
01362     // Create all ATSU objects
01363     ATSUStyle vertFontStyle;
01364     ATSUTextLayout horiTextLayout, vertTextLayout;
01365     createATSUObjects(horiFontStyle, vertFontStyle, horiTextLayout, vertTextLayout);
01366 
01367     // Try to get information about the face
01368     getFaceInfo(horiFontStyle, vertFontStyle, _family, _style,
01369                 _horiAscent, _horiDescent, _vertAscent, _vertDescent);
01370 
01371     // Determine the scale factor
01372     _scale = 1.f / (_horiAscent - _horiDescent);
01373 
01374     // Determine ascent
01375     _horiAscent *= _scale;
01376     _vertAscent = -0.5f;
01377 
01378     // Determine descent
01379     _horiDescent *= _scale;
01380     _vertDescent = 0.5f;
01381 
01382     // Set the parameters
01383     _param = param;
01384 
01385     // Switch off all font features
01386     ATSUFontFeatureType featureType = kAllTypographicFeaturesType;
01387     ATSUFontFeatureSelector featureSelector = kAllTypeFeaturesOffSelector;
01388     ATSUSetFontFeatures(horiFontStyle, 1, &featureType, &featureSelector);
01389     ATSUSetFontFeatures(vertFontStyle, 1, &featureType, &featureSelector);
01390 
01391     // Create all glyphs and the texture
01392     createGlyphs(horiFontStyle, vertFontStyle, horiTextLayout, vertTextLayout, param);
01393 
01394     // Dispose the layout objects
01395     ATSUDisposeTextLayout(horiTextLayout);
01396     ATSUDisposeTextLayout(vertTextLayout);
01397 
01398     // Dispose style objects
01399     ATSUDisposeStyle(horiFontStyle);
01400     ATSUDisposeStyle(vertFontStyle);
01401 }
01402 
01403 
01404 //----------------------------------------------------------------------
01405 // Destructor
01406 // Author: pdaehne
01407 //----------------------------------------------------------------------
01408 TextMacTXFFace::~TextMacTXFFace() {}
01409 
01410 
01411 //----------------------------------------------------------------------
01412 // Creates all glyphs and the texture
01413 // Author: pdaehne
01414 //----------------------------------------------------------------------
01415 void TextMacTXFFace::createGlyphs(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle,
01416                                   ATSUTextLayout horiTextLayout, ATSUTextLayout vertTextLayout,
01417                                   const TextTXFParam &param)
01418 {
01419     // Convert the unicode character string to utf16
01420     vector<UniChar> utf16Characters;
01421     convertUnicodeToUTF16(param.getCharacters(), utf16Characters);
01422 
01423     // Set the character string
01424     OSStatus result = ATSUSetTextPointerLocation(horiTextLayout, &(utf16Characters[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Characters.size());
01425     if (result != noErr)
01426         return;
01427 
01428     // Set the style object
01429     result = ATSUSetRunStyle(horiTextLayout, horiFontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
01430     if (result != noErr)
01431         return;
01432 
01433     // Get the layout records
01434     ATSLayoutRecord *layoutRecords;
01435     ItemCount numRecords;
01436     result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(horiTextLayout, kATSUFromTextBeginning,
01437                                                            kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
01438     if (result != noErr)
01439         return;
01440 
01441     // Determine horizontal glyph metrics
01442     vector<ATSGlyphScreenMetrics> horiMetrics;
01443     horiMetrics.resize(numRecords);
01444     result = ATSUGlyphGetScreenMetrics(horiFontStyle, numRecords, &(layoutRecords[0].glyphID), sizeof(ATSLayoutRecord), true, true, &(horiMetrics.front()));
01445     if (result != noErr)
01446     {
01447         ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
01448         return;
01449     }
01450 
01451     // Determine vertical glyph metrics
01452     vector<ATSGlyphScreenMetrics> vertMetrics;
01453     vertMetrics.resize(numRecords);
01454     result = ATSUGlyphGetScreenMetrics(vertFontStyle, numRecords, &(layoutRecords[0].glyphID), sizeof(ATSLayoutRecord), true, true, &(vertMetrics.front()));
01455     if (result != noErr)
01456     {
01457         ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
01458         return;
01459     }
01460 
01461     // Create all glyphs
01462     assert(numRecords == param.getCharacters().length() + 1);
01463     ItemCount j;
01464     for (j = 0; j < numRecords - 1; ++j)
01465     {
01466         ATSGlyphRef glyphID = layoutRecords[j].glyphID;
01467         wchar_t c = param.getCharacters()[j];
01468         _glyphMap.insert(GlyphMap::value_type(c, new TextMacTXFGlyph(c, _scale, horiMetrics[j], vertMetrics[j])));
01469     }
01470 
01471     // Calculate the positions of the glyphs on the texture
01472     prepareTexture(param);
01473     assert(_texture != NullFC);
01474     assert(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
01475 
01476     // Create the texture
01477     beginEditCP(_texture);
01478     for (j = 0; j < numRecords - 1; ++j)
01479     {
01480         wchar_t c = param.getCharacters()[j];
01481         TextTXFGlyph *glyph = _glyphMap[c];
01482 
01483         // Create pixmap
01484         ATSUTextMeasurement xPos = FloatToFixed(-horiMetrics[j].topLeft.x) - (layoutRecords[j].realPos & 0xffff0000);
01485         ATSUTextMeasurement yPos = FloatToFixed(horiMetrics[j].topLeft.y);
01486         UInt32 width = glyph->getPixmapWidth();
01487         UInt32 height = glyph->getPixmapHeight();
01488         UInt8 *dst = _texture->getData() + glyph->getX() + glyph->getY() * _texture->getWidth();
01489         UInt32 pitch = _texture->getWidth() - width;
01490         drawGlyph(horiTextLayout, layoutRecords[j], xPos, yPos, width, height, dst, pitch);
01491     }
01492     endEditCP(_texture);
01493 
01494     // Cleanup
01495     ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
01496 }
01497 
01498 
01499 //----------------------------------------------------------------------
01500 // Constructor
01501 // Author: pdaehne
01502 //----------------------------------------------------------------------
01503 TextMacTXFGlyph::TextMacTXFGlyph(Index glyphIndex, Real32 scale, const ATSGlyphScreenMetrics &horiMetrics, const ATSGlyphScreenMetrics &vertMetrics)
01504 : TextTXFGlyph()
01505 {
01506     _glyphIndex = glyphIndex;
01507     _scale = scale;
01508     _width = horiMetrics.width;
01509     _height = horiMetrics.height;
01510 
01511     // Determine horizontal glyph metrics
01512     _horiAdvance = horiMetrics.deviceAdvance.x * _scale;
01513     _horiBearingX = static_cast<int>(horiMetrics.topLeft.x);
01514     _horiBearingY = static_cast<int>(horiMetrics.topLeft.y);
01515 
01516     // Determine vertical glyph metrics
01517     _vertAdvance = vertMetrics.deviceAdvance.y * _scale;
01518     _vertBearingX = static_cast<int>(vertMetrics.topLeft.x);
01519     _vertBearingY = static_cast<int>(vertMetrics.topLeft.y);
01520 }
01521 
01522 
</