fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Text / OSGTextMacBackend.cpp
blobeabc3994929baa9d4361d6c746b9b6e714b8c03c
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright(C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
40 #ifdef _MSC_VER
41 # pragma warning (disable: 4786)
42 #endif
44 #include "OSGTextMacBackend.h"
45 #include "OSGBaseTypes.h"
47 #if (defined(__APPLE__) && !defined(__LP64__) && !OSG_APPLE_IOS) || defined(OSG_DO_DOC)
50 #include "OSGTextPixmapFace.h"
51 #include "OSGTextPixmapGlyph.h"
52 #include "OSGTextVectorFace.h"
53 #include "OSGTextVectorGlyph.h"
54 #include "OSGTextTXFFace.h"
55 #include "OSGTextTXFGlyph.h"
56 #include "OSGTextLayoutParam.h"
57 #include "OSGTextLayoutResult.h"
59 #include <iostream>
60 #include <algorithm>
61 #include <set>
63 #include <ApplicationServices/ApplicationServices.h>
65 using namespace std;
66 OSG_BEGIN_NAMESPACE
68 //----------------------------------------------------------------------
69 // MacOS X specific implementation of the TextVectorFace class
70 // Author: pdaehne
71 //----------------------------------------------------------------------
73 /*! \nohierarchy
76 class TextMacVectorFace: public TextVectorFace
78 public:
80 // Constructor
81 TextMacVectorFace(ATSUStyle horiFontStyle);
83 // Destructor
84 virtual ~TextMacVectorFace();
86 // Lays out one line of text
87 virtual void layout(const wstring &text, const TextLayoutParam &param,
88 TextLayoutResult &layoutResult);
90 protected:
92 // Creates a new Glyph object
93 virtual unique_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
95 private:
97 // The style objects that define the font
98 ATSUStyle _horiFontStyle;
99 ATSUStyle _vertFontStyle;
101 // The layout objects that handle the text layout
102 ATSUTextLayout _horiTextLayout;
103 ATSUTextLayout _vertTextLayout;
107 //----------------------------------------------------------------------
108 // MacOS X specific implementation of the TextVectorGlyph class
109 // Author: pdaehne
110 //----------------------------------------------------------------------
112 /*! \nohierarchy
115 class TextMacVectorGlyph: public TextVectorGlyph
117 public:
119 // Constructor
120 TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle);
122 // Destructor
123 virtual ~TextMacVectorGlyph();
127 //----------------------------------------------------------------------
128 // MacOS X specific implementation of the TextPixmapFace class
129 // Author: pdaehne
130 //----------------------------------------------------------------------
132 /*! \nohierarchy
135 class TextMacPixmapFace: public TextPixmapFace
137 public:
139 // Constructor
140 TextMacPixmapFace(ATSUStyle horiFontStyle);
142 // Destructor
143 virtual ~TextMacPixmapFace();
145 // Lays out one line of text
146 virtual void layout(const wstring &text, const TextLayoutParam &param,
147 TextLayoutResult &layoutResult);
149 protected:
151 // Creates a new Glyph object
152 virtual unique_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
154 private:
156 const TextPixmapGlyph &getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal);
158 // The style objects that define the font
159 ATSUStyle _horiFontStyle;
160 ATSUStyle _vertFontStyle;
162 // The layout objects that handle the text layout
163 ATSUTextLayout _horiTextLayout;
164 ATSUTextLayout _vertTextLayout;
168 //----------------------------------------------------------------------
169 // MacOS X specific implementation of the TextPixmapGlyph class
170 // Author: pdaehne
171 //----------------------------------------------------------------------
173 /*! \nohierarchy
176 class TextMacPixmapGlyph: public TextPixmapGlyph
178 public:
180 // Constructor
181 TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
182 Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
183 Real32 vertAdvance, Int32 vertBearingX, Int32 vertBearingY,
184 UInt8 *pixmap);
186 // Destructor
187 virtual ~TextMacPixmapGlyph();
191 //----------------------------------------------------------------------
192 // MacOS X specific implementation of the TextTXFFace class
193 // Author: pdaehne
194 //----------------------------------------------------------------------
196 /*! \nohierarchy
199 class TextMacTXFFace: public TextTXFFace
201 public:
203 // Constructor
204 TextMacTXFFace(ATSUStyle horiFontStyle, const TextTXFParam &param);
206 // Destructor
207 virtual ~TextMacTXFFace();
209 private:
211 void createGlyphs(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle,
212 ATSUTextLayout horiTextLayout, ATSUTextLayout vertTextLayout,
213 const TextTXFParam &param);
217 //----------------------------------------------------------------------
218 // MacOS X specific implementation of the TextTXFGlyph class
219 // Author: pdaehne
220 //----------------------------------------------------------------------
222 /*! \nohierarchy
225 class TextMacTXFGlyph: public TextTXFGlyph
227 public:
229 // Constructor
230 TextMacTXFGlyph(Index glyphIndex, Real32 scale, const ATSGlyphScreenMetrics &horiMetrics, const ATSGlyphScreenMetrics &vertMetrics);
232 // Destructor
233 virtual ~TextMacTXFGlyph();
237 //----------------------------------------------------------------------
238 // Constructor
239 // Author: pdaehne
240 //----------------------------------------------------------------------
241 TextMacBackend::TextMacBackend(): TextBackend() {}
244 //----------------------------------------------------------------------
245 // Destructor
246 // Author: pdaehne
247 //----------------------------------------------------------------------
248 TextMacBackend::~TextMacBackend() {}
251 //----------------------------------------------------------------------
252 // Returns the family name of a font
253 // Author: pdaehne
254 //----------------------------------------------------------------------
255 static string getFamilyName(ATSUFontID fontID)
257 ItemCount fontNameIndex;
258 OSStatus result = ATSUFindFontName(fontID, kFontFamilyName, kFontNoPlatformCode,
259 kFontNoScriptCode, kFontNoLanguageCode,
260 0, 0, 0, &fontNameIndex);
261 if (result != noErr)
262 return string();
263 ByteCount actualNameLength;
264 result = ATSUGetIndFontName(fontID, fontNameIndex, 0, 0, &actualNameLength,
265 0, 0, 0, 0);
266 if ((result != noErr) || (actualNameLength == 0))
267 return string();
268 vector<char> name;
269 name.resize(actualNameLength);
270 FontPlatformCode fontNamePlatform;
271 result = ATSUGetIndFontName(fontID, fontNameIndex, actualNameLength, &(name.front()), 0,
272 0, &fontNamePlatform, 0, 0);
273 if ((result != noErr) || (actualNameLength == 0))
274 return string();
275 CFStringRef str = 0;
276 switch (fontNamePlatform)
278 case kFontUnicodePlatform:
279 case kFontMicrosoftPlatform: // ???
280 str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
281 actualNameLength, kCFStringEncodingUnicode, false);
282 break;
283 case kFontMacintoshPlatform:
284 str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
285 actualNameLength, kCFStringEncodingMacRoman, false);
286 break;
287 default:
288 return string();
290 if (str == 0)
291 return string();
292 CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, ' ');
293 CFRelease(str);
294 if (data == 0)
295 return string();
296 string familyName(reinterpret_cast<const char*>(CFDataGetBytePtr(data)),
297 static_cast<string::size_type>(CFDataGetLength(data)));
298 CFRelease(data);
299 return familyName;
303 //----------------------------------------------------------------------
304 // Tries to find a font
305 // Author: pdaehne
306 //----------------------------------------------------------------------
307 static ATSUStyle findFont(const string &family, TextFace::Style style, UInt32 size)
309 // Handle generic family names
310 string f;
311 if (family == "SERIF")
312 f = "Times New Roman";
313 else if (family == "SANS")
314 f = "Arial";
315 else if (family == "TYPEWRITER")
316 f = "Courier";
317 else
318 f = family;
320 // Get the number of fonts installed
321 ItemCount fontCount;
322 OSStatus result = ATSUFontCount(&fontCount);
323 if ((result != noErr) || (fontCount == 0))
324 return 0;
326 // Get the IDs of all fonts
327 vector<ATSUFontID> fontIDs;
328 fontIDs.resize(fontCount);
329 result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
330 if (result != noErr)
331 return 0;
333 // Try to find the font
334 ItemCount i;
335 for (i = 0; i < fontCount; ++i)
337 string familyName = getFamilyName(fontIDs[i]);
338 if (familyName == f)
339 break;
341 if (i >= fontCount)
342 return 0;
343 ATSUFontID fontID = fontIDs[i];
345 FMFontFamily fontFamily;
346 result = FMGetFontFamilyInstanceFromFont(fontID, &fontFamily, 0);
347 if (result != noErr)
348 return 0;
349 FMFontStyle fStyle;
350 switch (style)
352 default:
353 FWARNING(("Invalid font style parameter.\n"));
354 // intentionally fall through
355 case TextFace::STYLE_PLAIN: fStyle = normal; break;
356 case TextFace::STYLE_BOLD: fStyle = bold; break;
357 case TextFace::STYLE_ITALIC: fStyle = italic; break;
358 case TextFace::STYLE_BOLDITALIC: fStyle = bold | italic; break;
360 result = FMGetFontFromFontFamilyInstance(fontFamily, fStyle, &fontID, 0);
361 if ((result != noErr) || (fontID == kATSUInvalidFontID))
362 return 0;
364 // Create style object
365 ATSUStyle fontStyle;
366 result = ATSUCreateStyle(&fontStyle);
367 if (result != noErr)
368 return 0;
370 // Set style attributes
371 //Boolean bold = ((style == TextFace::STYLE_BOLD) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
372 //Boolean italic = ((style == TextFace::STYLE_ITALIC) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
373 Fixed fontSize = IntToFixed(size);
374 ATSUAttributeTag attributeTags[] = { kATSUFontTag, /*kATSUQDBoldfaceTag, kATSUQDItalicTag,*/ kATSUSizeTag };
375 ByteCount attributeSizes[] = { sizeof(fontID), /*sizeof(bold), sizeof(italic),*/ sizeof(fontSize) };
376 ATSUAttributeValuePtr attributeValues[] = { &fontID, /*&bold, &italic,*/ &fontSize };
377 result = ATSUSetAttributes(fontStyle, /*4*/2, attributeTags, attributeSizes, attributeValues);
378 if (result != noErr)
380 ATSUDisposeStyle(fontStyle);
381 return 0;
384 return fontStyle;
388 //----------------------------------------------------------------------
389 // Creates a new vector face
390 // Author: pdaehne
391 //----------------------------------------------------------------------
392 TextVectorFaceTransitPtr TextMacBackend::createVectorFace(
393 const string &family, TextFace::Style style)
395 TextVectorFaceTransitPtr retVal;
397 // Try to find the font
398 ATSUStyle horiFontStyle = findFont(family, style, 1000);
399 if (horiFontStyle != 0)
401 // Switch off hinting
402 ATSStyleRenderingOptions styleRenderingOptions = kATSStyleNoHinting;
403 ATSUAttributeTag attributeTag = kATSUStyleRenderingOptionsTag;
404 ByteCount attributeSize = sizeof(styleRenderingOptions);
405 ATSUAttributeValuePtr attributeValue = &styleRenderingOptions;
406 OSStatus result = ATSUSetAttributes(horiFontStyle, 1, &attributeTag, &attributeSize, &attributeValue);
407 // We don't care for errors - this is not really an important attribute
409 // Create the new face object
410 retVal = new TextMacVectorFace(horiFontStyle);
413 return retVal;
417 //----------------------------------------------------------------------
418 // Creates a new pixmap face
419 // Author: pdaehne
420 //----------------------------------------------------------------------
421 TextPixmapFaceTransitPtr TextMacBackend::createPixmapFace(
422 const string &family, TextFace::Style style, UInt32 size)
424 TextPixmapFaceTransitPtr retVal;
426 // Try to find the font
427 ATSUStyle horiFontStyle = findFont(family, style, size);
428 if (horiFontStyle != 0)
430 retVal = new TextMacPixmapFace(horiFontStyle);
433 return retVal;
437 //----------------------------------------------------------------------
438 // Creates a new TXF face
439 // Author: pdaehne
440 //----------------------------------------------------------------------
441 TextTXFFaceTransitPtr TextMacBackend::createTXFFace(
442 const string &family, TextFace::Style style, const TextTXFParam &param)
444 TextTXFFaceTransitPtr retVal;
446 // Try to find the font
447 ATSUStyle horiFontStyle = findFont(family, style, param.size);
448 if (horiFontStyle != 0)
450 // Create the new face object
451 retVal = new TextMacTXFFace(horiFontStyle, param);
454 return retVal;
458 //----------------------------------------------------------------------
459 // Returns the names of all font families available
460 // Author: pdaehne
461 //----------------------------------------------------------------------
462 void TextMacBackend::getFontFamilies(vector<string> &families)
464 families.clear();
466 // Get the number of fonts installed
467 ItemCount fontCount;
468 OSStatus result = ATSUFontCount(&fontCount);
469 if ((result != noErr) || (fontCount == 0))
470 return;
472 // Get the IDs of all fonts
473 vector<ATSUFontID> fontIDs;
474 fontIDs.resize(fontCount);
475 result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
476 if (result != noErr)
477 return;
479 // Put all font families into the vector
480 ItemCount i;
481 set<string> familySet;
482 for (i = 0; i < fontCount; ++i)
484 string familyName = getFamilyName(fontIDs[i]);
485 if (familyName.empty() == false)
486 familySet.insert(familyName);
488 families.assign(familySet.begin(), familySet.end());
492 //----------------------------------------------------------------------
493 // Tries to get information about the face
494 // Author: pdaehne
495 //----------------------------------------------------------------------
496 static void getFaceInfo(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle, string &family, TextFace::Style &style,
497 Real32 &horiAscent, Real32 &horiDescent,
498 Real32 &vertAscent, Real32 &vertDescent)
500 // Try to get the family name
501 ATSUFontID fontID;
502 OSStatus result = ATSUGetAttribute(horiFontStyle, kATSUFontTag, sizeof(fontID), &fontID, 0);
503 if (((result == noErr) || (result == kATSUNotSetErr)) && (fontID != kATSUInvalidFontID))
504 family = getFamilyName(fontID);
505 else
506 family.erase();
508 // Try to get style
509 Boolean bold;
510 result = ATSUGetAttribute(horiFontStyle, kATSUQDBoldfaceTag, sizeof(bold), &bold, 0);
511 if ((result != noErr) && (result != kATSUNotSetErr))
512 bold = false;
513 Boolean italic;
514 result = ATSUGetAttribute(horiFontStyle, kATSUQDItalicTag, sizeof(italic), &italic, 0);
515 if ((result != noErr) && (result != kATSUNotSetErr))
516 italic = false;
517 style = (bold == TRUE) ?
518 (italic == TRUE ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD) :
519 (italic == TRUE ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN);
521 // Try to get ascent
522 ATSUTextMeasurement measurement;
523 result = ATSUGetAttribute(horiFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
524 horiAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
525 result = ATSUGetAttribute(vertFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
526 vertAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
528 // Try to get descent
529 result = ATSUGetAttribute(horiFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
530 horiDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
531 result = ATSUGetAttribute(vertFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
532 vertDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
536 //----------------------------------------------------------------------
537 // Creates all ATSU objects needed by a face
538 // Author: pdaehne
539 //----------------------------------------------------------------------
540 static void createATSUObjects(ATSUStyle horiFontStyle, ATSUStyle &vertFontStyle, ATSUTextLayout &horiTextLayout, ATSUTextLayout &vertTextLayout)
542 // Create vertical style object
543 OSStatus result = ATSUCreateAndCopyStyle(horiFontStyle, &vertFontStyle);
544 if (result != noErr)
545 vertFontStyle = 0;
546 else
548 ATSUVerticalCharacterType verticalCharacterType = kATSUStronglyVertical;
549 ATSUAttributeTag attributeTags[] = { kATSUVerticalCharacterTag };
550 ByteCount attributeSizes[] = { sizeof(verticalCharacterType) };
551 ATSUAttributeValuePtr attributeValues[] = { &verticalCharacterType };
552 result = ATSUSetAttributes(vertFontStyle, 1, attributeTags, attributeSizes, attributeValues);
555 // Create the layout objects
556 result = ATSUCreateTextLayout(&horiTextLayout);
557 if (result != noErr)
558 horiTextLayout = 0;
559 result = ATSUCreateAndCopyTextLayout(horiTextLayout, &vertTextLayout);
560 if (result != noErr)
561 vertTextLayout = 0;
562 else
564 Fixed lineRotation = IntToFixed(-90);
565 ATSUAttributeTag layoutAttributeTags[] = { kATSULineRotationTag };
566 ByteCount layoutAttributeSizes[] = { sizeof(lineRotation) };
567 ATSUAttributeValuePtr layoutAttributeValues[] = { &lineRotation };
568 result = ATSUSetLayoutControls(vertTextLayout, 1, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
573 //----------------------------------------------------------------------
574 // Constructor
575 // Author: pdaehne
576 //----------------------------------------------------------------------
577 TextMacVectorFace::TextMacVectorFace(ATSUStyle horiFontStyle)
578 : TextVectorFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
580 // Create all ATSU objects
581 createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
583 // Try to get information about the face
584 getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
585 _horiAscent, _horiDescent, _vertAscent, _vertDescent);
587 // Determine the scale factor
588 _scale = 1.f / (_horiAscent - _horiDescent);
590 // Determine ascent
591 _horiAscent *= _scale;
592 _vertAscent = -0.5f;
594 // Determine descent
595 _horiDescent *= _scale;
596 _vertDescent = 0.5f;
600 //----------------------------------------------------------------------
601 // Destructor
602 // Author: pdaehne
603 //----------------------------------------------------------------------
604 TextMacVectorFace::~TextMacVectorFace()
606 // Dispose the layout objects
607 ATSUDisposeTextLayout(_horiTextLayout);
608 ATSUDisposeTextLayout(_vertTextLayout);
610 // Dispose style objects
611 ATSUDisposeStyle(_horiFontStyle);
612 ATSUDisposeStyle(_vertFontStyle);
616 //----------------------------------------------------------------------
617 // Converts a unicode string to utf16
618 // RFC2781: UTF-16, an encoding of ISO 10646
619 // Author: pdaehne
620 //----------------------------------------------------------------------
621 static void convertUnicodeToUTF16(const wstring &text, vector<UniChar> &utf16Text)
623 UniCharCount i, textTotalLength = text.length();
624 utf16Text.clear();
625 utf16Text.reserve(textTotalLength);
626 for (i = 0; i < textTotalLength; ++i)
628 wchar_t unicode = text[i];
629 if (unicode < 0x10000)
630 utf16Text.push_back(unicode);
631 else if (unicode < 0x110000)
633 unsigned long u = unicode - 0x10000;
634 utf16Text.push_back(0xd800 | (u >> 10));
635 utf16Text.push_back(0xdc00 | (u & 0x3ff));
641 //----------------------------------------------------------------------
642 // Lays out one line of text
643 // Author: pdaehne
644 //----------------------------------------------------------------------
645 void TextMacVectorFace::layout(const wstring &text, const TextLayoutParam &param,
646 TextLayoutResult &layoutResult)
648 // Initialize return values
649 layoutResult.clear();
650 if (param.horizontal == true)
651 layoutResult.textBounds[1] = _horiAscent - _horiDescent;
652 else
653 layoutResult.textBounds[0] = _vertDescent - _vertAscent;
654 layoutResult.lineBounds.push_back(layoutResult.textBounds);
656 // Convert the unicode string to utf16
657 vector<UniChar> utf16Text;
658 convertUnicodeToUTF16(text, utf16Text);
659 if (utf16Text.empty() == true)
660 return;
662 // Check whether we have to use the horizontal or vertical ATSUI objects
663 ATSUStyle fontStyle;
664 ATSUTextLayout textLayout;
665 if (param.horizontal == true)
667 fontStyle = _horiFontStyle;
668 textLayout = _horiTextLayout;
670 else
672 fontStyle = _vertFontStyle;
673 textLayout = _vertTextLayout;
676 // Set the length
677 Real32 length = param.getLength(0);
678 Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
679 ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length / _scale);
680 ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
681 ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
682 ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
683 ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
685 // Set the text
686 OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
687 if (result != noErr)
688 return;
690 // Set the style object
691 result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
692 if (result != noErr)
693 return;
695 // Get the layout records
696 ATSLayoutRecord *layoutRecords;
697 ItemCount numRecords;
698 result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
699 kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
700 if (result != noErr)
701 return;
702 Fixed *deltaYs;
703 ItemCount numDeltaYs;
704 result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
705 kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
706 if (result != noErr)
707 deltaYs = 0;
709 // Calculate the positions of the glyphs
710 layoutResult.indices.reserve(numRecords);
711 layoutResult.positions.reserve(numRecords);
712 ItemCount j;
713 Vec2f currPos;
714 for (j = 0; j < numRecords; ++j)
716 ATSGlyphRef glyphID = layoutRecords[j].glyphID;
717 currPos[0] = FixedToFloat(layoutRecords[j].realPos) * _scale;
718 currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) * _scale: 0.f;
719 const TextVectorGlyph &glyph = getVectorGlyph(glyphID);
720 if (param.horizontal == true)
722 currPos[0] += glyph.getHoriBearingX();
723 currPos[1] += glyph.getHoriBearingY();
725 else
727 float h = currPos.x();
728 currPos[0] = currPos.y() + glyph.getVertBearingX();
729 currPos[1] = -h + glyph.getVertBearingY();
731 if (glyphID != kATSDeletedGlyphcode)
733 layoutResult.indices.push_back(glyphID);
734 layoutResult.positions.push_back(currPos);
738 // Cleanup
739 if (deltaYs != 0)
740 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
741 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
743 // Adjust the origin depending on the major and the minor alignment
744 adjustLineOrigin(param, currPos, layoutResult);
746 // Determine text bounds / line bounds
747 if (param.horizontal == true)
748 layoutResult.textBounds[0] = osgAbs(currPos.x());
749 else
750 layoutResult.textBounds[1] = osgAbs(currPos.y());
751 OSG_ASSERT(layoutResult.lineBounds.empty() == false);
752 layoutResult.lineBounds.front() = layoutResult.textBounds;
756 //----------------------------------------------------------------------
757 // Helper object used by the decompose callback functions
758 // Author: pdaehne
759 //----------------------------------------------------------------------
760 typedef struct UserData
762 Real32 scale;
763 Vec2f offset;
764 TextVectorGlyph::Outline &outline;
765 inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
766 : scale(s), offset(off), outline(o)
769 UserData;
772 //----------------------------------------------------------------------
773 // callback function that starts a new contour
774 // Author: pdaehne
775 //----------------------------------------------------------------------
776 static OSStatus quadraticNewPathCallback(void *callBackDataPtr)
778 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
780 // We start a new contour
781 userData->outline.push_back(TextVectorGlyph::Contour());
783 // Continue
784 return noErr;
788 //----------------------------------------------------------------------
789 // callback function that adds a line to the contour
790 // Author: pdaehne
791 //----------------------------------------------------------------------
792 static OSStatus quadraticLineCallback(const Float32Point *pt1, const Float32Point *pt2, void *callBackDataPtr)
794 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
796 // When this is the first segment, we have to put the first point into the contour
797 if (userData->outline.back().empty() == true)
799 Vec2f p(pt1->x, -pt1->y);
800 p *= userData->scale;
801 p -= userData->offset;
802 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
805 // We have a point on the line
806 Vec2f p(pt2->x, -pt2->y);
807 p *= userData->scale;
808 p -= userData->offset;
809 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
811 // Continue
812 return noErr;
816 //----------------------------------------------------------------------
817 // callback function that adds a quadratic Bezier spline to the contour
818 // Author: pdaehne
819 //----------------------------------------------------------------------
820 static OSStatus quadraticCurveCallback(const Float32Point *pt1, const Float32Point *controlPt, const Float32Point *pt2, void *callBackDataPtr)
822 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
824 // When this is the first segment, we have to put the first point into the contour
825 if (userData->outline.back().empty() == true)
827 Vec2f p(pt1->x, -pt1->y);
828 p *= userData->scale;
829 p -= userData->offset;
830 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
833 // We have a control point and a point on the line
834 Vec2f p(controlPt->x, -controlPt->y);
835 p *= userData->scale;
836 p -= userData->offset;
837 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
838 p.setValues(pt2->x, -pt2->y);
839 p *= userData->scale;
840 p -= userData->offset;
841 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
843 // Continue
844 return noErr;
848 //----------------------------------------------------------------------
849 // callback function that closes a contour
850 // Author: pdaehne
851 //----------------------------------------------------------------------
852 OSStatus quadraticClosePathCallback(void *callBackDataPtr)
854 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
856 // Check if the contour is valid, i.e. if it has more than three points.
857 // When not, we simply delete the contour.
858 if (userData->outline.back().size() < 3)
859 userData->outline.erase(userData->outline.end() - 1);
861 // Continue
862 return noErr;
866 //----------------------------------------------------------------------
867 // callback function that starts a new contour
868 // Author: pdaehne
869 //----------------------------------------------------------------------
870 static OSStatus cubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
872 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
874 // We start a new contour
875 userData->outline.push_back(TextVectorGlyph::Contour());
877 // We have a point on the line
878 Vec2f p(pt->x, -pt->y);
879 p *= userData->scale;
880 p -= userData->offset;
881 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
883 // Continue
884 return noErr;
888 //----------------------------------------------------------------------
889 // callback function that adds a line to the contour
890 // Author: pdaehne
891 //----------------------------------------------------------------------
892 static OSStatus cubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
894 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
896 // We have a point on the line
897 Vec2f p(pt->x, -pt->y);
898 p *= userData->scale;
899 p -= userData->offset;
900 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
902 // Continue
903 return noErr;
907 //----------------------------------------------------------------------
908 // callback function that adds a cubic Bezier spline to the contour
909 // Author: pdaehne
910 //----------------------------------------------------------------------
911 static OSStatus cubicCurveToCallback(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *callBackDataPtr)
913 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
915 // We have two control points and a point on the line
916 Vec2f p(pt1->x, -pt1->y);
917 p *= userData->scale;
918 p -= userData->offset;
919 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
920 p.setValues(pt2->x, -pt2->y);
921 p *= userData->scale;
922 p -= userData->offset;
923 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
924 p.setValues(pt3->x, -pt3->y);
925 p *= userData->scale;
926 p -= userData->offset;
927 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
929 // Continue
930 return noErr;
934 //----------------------------------------------------------------------
935 // callback function that closes a contour
936 // Author: pdaehne
937 //----------------------------------------------------------------------
938 static OSStatus cubicClosePathCallback(void *callBackDataPtr)
940 UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
942 // Check if the contour is valid, i.e. if it has more than two points.
943 // When not, we simply delete the contour.
944 if (userData->outline.back().size() < 3)
945 userData->outline.erase(userData->outline.end() - 1);
947 // Continue
948 return noErr;
952 //----------------------------------------------------------------------
953 // Creates a new Glyph object
954 // Author: pdaehne
955 //----------------------------------------------------------------------
956 unique_ptr<TextVectorGlyph> TextMacVectorFace::createGlyph(TextGlyph::Index glyphIndex)
958 // We cannot create glyphs for invalid glyph indices
959 if (glyphIndex == TextGlyph::INVALID_INDEX)
960 return unique_ptr<TextVectorGlyph>();
962 // Create and return the new glyph object
963 return unique_ptr<TextVectorGlyph>(new TextMacVectorGlyph(glyphIndex, _scale, _horiFontStyle, _vertFontStyle));
967 //----------------------------------------------------------------------
968 // Constructor
969 // Author: pdaehne
970 //----------------------------------------------------------------------
971 TextMacVectorGlyph::TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle)
972 : TextVectorGlyph()
974 _glyphIndex = glyphIndex;
976 // Determine horizontal glyph metrics
977 GlyphID glyphID = _glyphIndex;
978 ATSGlyphScreenMetrics glyphScreenMetrics;
979 OSStatus result = ATSUGlyphGetScreenMetrics(horiFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
980 if (result == noErr)
982 _width = glyphScreenMetrics.width * scale;
983 _height = glyphScreenMetrics.height * scale;
984 _horiAdvance = glyphScreenMetrics.deviceAdvance.x * scale;
985 _horiBearingX = glyphScreenMetrics.topLeft.x * scale;
986 _horiBearingY = glyphScreenMetrics.topLeft.y * scale;
989 // Determine vertical glyph metrics
990 result = ATSUGlyphGetScreenMetrics(vertFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
991 if (result == noErr)
993 _width = glyphScreenMetrics.width * scale;
994 _height = glyphScreenMetrics.height * scale;
995 _vertAdvance = glyphScreenMetrics.deviceAdvance.y * scale;
996 _vertBearingX = glyphScreenMetrics.topLeft.x * scale;
997 _vertBearingY = glyphScreenMetrics.topLeft.y * scale;
1000 // Get the outlines
1001 ATSCurveType curveType;
1002 result = ATSUGetNativeCurveType(horiFontStyle, &curveType);
1003 if (result != noErr)
1004 return;
1005 if (curveType == kATSQuadCurveType)
1007 // This is quite ugly, we should do this only once for all glyphs.
1008 // But on MacOS X, this should be a NOP, anyway.
1009 ATSQuadraticNewPathUPP newPathProc = NewATSQuadraticNewPathUPP(&quadraticNewPathCallback);
1010 ATSQuadraticLineUPP lineProc = NewATSQuadraticLineUPP(&quadraticLineCallback);
1011 ATSQuadraticCurveUPP curveProc = NewATSQuadraticCurveUPP(&quadraticCurveCallback);
1012 ATSQuadraticClosePathUPP closePathProc = NewATSQuadraticClosePathUPP(&quadraticClosePathCallback);
1013 UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
1014 OSStatus callbackResult;
1015 result = ATSUGlyphGetQuadraticPaths(horiFontStyle, glyphID, newPathProc, lineProc, curveProc, closePathProc, &userData, &callbackResult);
1016 DisposeATSQuadraticClosePathUPP(closePathProc);
1017 DisposeATSQuadraticCurveUPP(curveProc);
1018 DisposeATSQuadraticLineUPP(lineProc);
1019 DisposeATSQuadraticNewPathUPP(newPathProc);
1021 else if (curveType == kATSCubicCurveType)
1023 // This is quite ugly, we should do this only once for all glyphs.
1024 // But on MacOS X, this should be a NOP, anyway.
1025 ATSCubicMoveToUPP moveToProc = NewATSCubicMoveToUPP(&cubicMoveToCallback);
1026 ATSCubicLineToUPP lineToProc = NewATSCubicLineToUPP(&cubicLineToCallback);
1027 ATSCubicCurveToUPP curveToProc = NewATSCubicCurveToUPP(&cubicCurveToCallback);
1028 ATSCubicClosePathUPP closePathProc = NewATSCubicClosePathUPP(&cubicClosePathCallback);
1029 UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
1030 OSStatus callbackResult;
1031 ATSUGlyphGetCubicPaths(horiFontStyle, glyphID, moveToProc, lineToProc, curveToProc, closePathProc, &userData, &callbackResult);
1032 DisposeATSCubicClosePathUPP(closePathProc);
1033 DisposeATSCubicCurveToUPP(curveToProc);
1034 DisposeATSCubicLineToUPP(lineToProc);
1035 DisposeATSCubicMoveToUPP(moveToProc);
1040 //----------------------------------------------------------------------
1041 // Destructor
1042 // Author: pdaehne
1043 //----------------------------------------------------------------------
1044 TextMacVectorGlyph::~TextMacVectorGlyph() {}
1047 //----------------------------------------------------------------------
1048 // Constructor
1049 // Author: pdaehne
1050 //----------------------------------------------------------------------
1051 TextMacPixmapFace::TextMacPixmapFace(ATSUStyle horiFontStyle)
1052 : TextPixmapFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
1054 // Create all ATSU objects
1055 createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
1057 // Try to get information about the face
1058 getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
1059 _horiAscent, _horiDescent, _vertAscent, _vertDescent);
1061 // Determine the size
1062 Fixed size;
1063 OSStatus result = ATSUGetAttribute(_horiFontStyle, kATSUSizeTag, sizeof(size), &size, 0);
1064 _size = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToInt(size) : 0;
1068 //----------------------------------------------------------------------
1069 // Destructor
1070 // Author: pdaehne
1071 //----------------------------------------------------------------------
1072 TextMacPixmapFace::~TextMacPixmapFace()
1074 // Dispose the layout objects
1075 ATSUDisposeTextLayout(_horiTextLayout);
1076 ATSUDisposeTextLayout(_vertTextLayout);
1078 // Dispose style objects
1079 ATSUDisposeStyle(_horiFontStyle);
1080 ATSUDisposeStyle(_vertFontStyle);
1084 //----------------------------------------------------------------------
1085 // Lays out one line of text
1086 // Author: pdaehne
1087 //----------------------------------------------------------------------
1088 void TextMacPixmapFace::layout(const wstring &text, const TextLayoutParam &param,
1089 TextLayoutResult &layoutResult)
1091 // Initialize return values
1092 layoutResult.clear();
1093 if (param.horizontal == true)
1094 layoutResult.textBounds[1] = _horiAscent - _horiDescent;
1095 else
1096 layoutResult.textBounds[0] = _vertDescent - _vertAscent;
1097 layoutResult.lineBounds.push_back(layoutResult.textBounds);
1099 // Convert the unicode string to utf16
1100 vector<UniChar> utf16Text;
1101 convertUnicodeToUTF16(text, utf16Text);
1102 if (utf16Text.empty() == true)
1103 return;
1105 // Check whether we have to use the horizontal or vertical ATSUI objects
1106 ATSUStyle fontStyle;
1107 ATSUTextLayout textLayout;
1108 if (param.horizontal == true)
1110 fontStyle = _horiFontStyle;
1111 textLayout = _horiTextLayout;
1113 else
1115 fontStyle = _vertFontStyle;
1116 textLayout = _vertTextLayout;
1119 // Set the length
1120 Real32 length = param.getLength(0);
1121 Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
1122 ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length);
1123 ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
1124 ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
1125 ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
1126 ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
1128 // Set the text
1129 OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
1130 if (result != noErr)
1131 return;
1133 // Set the style object
1134 result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
1135 if (result != noErr)
1136 return;
1138 // Get the layout records
1139 ATSLayoutRecord *layoutRecords;
1140 ItemCount numRecords;
1141 result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
1142 kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
1143 if (result != noErr)
1144 return;
1145 Fixed *deltaYs;
1146 ItemCount numDeltaYs;
1147 result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
1148 kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
1149 if (result != noErr)
1150 deltaYs = 0;
1152 // Calculate the positions of the glyphs
1153 layoutResult.indices.reserve(numRecords);
1154 layoutResult.positions.reserve(numRecords);
1155 ItemCount j;
1156 Vec2f currPos;
1157 for (j = 0; j < numRecords; ++j)
1159 ATSGlyphRef glyphID = layoutRecords[j].glyphID;
1160 currPos[0] = FixedToFloat(layoutRecords[j].realPos);
1161 currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) : 0.f;
1162 const TextPixmapGlyph &glyph = getPixmapGlyph(layoutRecords[j], param.horizontal);
1163 if (param.horizontal == true)
1165 currPos[0] += glyph.getHoriBearingX();
1166 currPos[1] += glyph.getHoriBearingY();
1168 else
1170 float h = currPos.x();
1171 currPos[0] = currPos.y() + glyph.getVertBearingX();
1172 currPos[1] = -h + glyph.getVertBearingY();
1174 if (glyphID != kATSDeletedGlyphcode)
1176 layoutResult.indices.push_back(glyphID);
1177 layoutResult.positions.push_back(currPos);
1181 // Cleanup
1182 if (deltaYs != 0)
1183 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
1184 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
1186 // Adjust the origin depending on the major and the minor alignment
1187 adjustLineOrigin(param, currPos, layoutResult);
1189 // Determine text bounds / line bounds
1190 if (param.horizontal == true)
1191 layoutResult.textBounds[0] = osgAbs(currPos.x());
1192 else
1193 layoutResult.textBounds[1] = osgAbs(currPos.y());
1194 OSG_ASSERT(layoutResult.lineBounds.empty() == false);
1195 layoutResult.lineBounds.front() = layoutResult.textBounds;
1199 //----------------------------------------------------------------------
1200 // Creates a new Glyph object
1201 // Author: pdaehne
1202 //----------------------------------------------------------------------
1203 unique_ptr<TextPixmapGlyph> TextMacPixmapFace::createGlyph(TextGlyph::Index glyphIndex)
1205 return unique_ptr<TextPixmapGlyph>();
1209 //----------------------------------------------------------------------
1210 // Renders a glyph into a memory buffer
1211 // Author: pdaehne
1212 //----------------------------------------------------------------------
1213 static void drawGlyph(ATSUTextLayout textLayout, const ATSLayoutRecord &layoutRecord,
1214 ATSUTextMeasurement xPos, ATSUTextMeasurement yPos,
1215 UInt32 width, UInt32 height, UInt8 *dst, UInt32 pitch)
1217 // No need to draw invisible glyphs
1218 if ((width == 0) || (height == 0))
1219 return;
1221 // Create offscreen GWorld
1222 GWorldPtr offscreenGWorld;
1223 Rect boundsRect;
1224 SetRect(&boundsRect, 0, 0, width, height);
1225 QDErr qdResult = NewGWorld(&offscreenGWorld, 32, &boundsRect, 0, 0, 0);
1226 if (qdResult != noErr)
1227 return;
1229 // Get the pixel buffer of the offscreen GWorld
1230 if (LockPixels(GetGWorldPixMap(offscreenGWorld)) == FALSE)
1232 DisposeGWorld(offscreenGWorld);
1233 return;
1235 Ptr src = GetPixBaseAddr(GetGWorldPixMap(offscreenGWorld));
1236 if (src == 0)
1238 UnlockPixels(GetGWorldPixMap(offscreenGWorld));
1239 DisposeGWorld(offscreenGWorld);
1240 return;
1243 // Initialize and activate the offscreen GWorld
1244 CGrafPtr port;
1245 GDHandle gdh;
1246 GetGWorld(&port, &gdh);
1247 SetGWorld(offscreenGWorld, 0);
1248 RGBColor gBlackColour = { 0x0000, 0x0000, 0x0000 };
1249 RGBBackColor(&gBlackColour);
1250 EraseRect(&boundsRect);
1251 RGBColor gWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
1252 RGBForeColor(&gWhiteColour);
1254 // Draw the text
1255 UniCharArrayOffset charOffset = layoutRecord.originalOffset >> 1;
1256 UniCharCount charCount = (layoutRecord.flags & kATSGlyphInfoByteSizeMask) >> 1;
1257 OSStatus result = ATSUDrawText(textLayout, charOffset, charCount, xPos, yPos);
1258 if (result == noErr)
1260 long bpl = GetPixRowBytes(GetGWorldPixMap(offscreenGWorld));
1261 src += bpl * (height - 1);
1262 Ptr src2;
1263 UInt32 x, y;
1264 for (y = 0; y < height; ++y)
1266 src2 = src + 1;
1267 for (x = 0; x < width; ++x)
1269 *dst++ = *src2;
1270 src2+= 4;
1272 src -= bpl;
1273 dst += pitch;
1277 // Deactivate and destroy the offscreen GWorld
1278 SetGWorld(port, gdh);
1279 UnlockPixels(GetGWorldPixMap(offscreenGWorld));
1280 DisposeGWorld(offscreenGWorld);
1284 //----------------------------------------------------------------------
1285 // Returns information about a glyph.
1286 // Author: pdaehne
1287 //----------------------------------------------------------------------
1288 const TextPixmapGlyph &TextMacPixmapFace::getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal)
1290 ATSGlyphRef glyphID = layoutRecord.glyphID;
1291 if (glyphID == kATSDeletedGlyphcode)
1292 return _emptyGlyph;
1294 // Try to find the glyph in the map of glyphs
1295 GlyphMap::const_iterator it = _glyphMap.find(glyphID);
1296 if (it != _glyphMap.end())
1298 OSG_ASSERT(it->second != 0);
1299 return *(it->second);
1302 // We did not find the glyph, so we have to create it
1303 ATSUTextMeasurement xPos = 0, yPos = 0;
1305 // Determine horizontal glyph metrics
1306 ATSGlyphScreenMetrics glyphScreenMetrics;
1307 OSStatus result = ATSUGlyphGetScreenMetrics(_horiFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
1308 if (result != noErr)
1309 return _emptyGlyph;
1310 Real32 horiAdvance = glyphScreenMetrics.deviceAdvance.x;
1311 UInt32 width = glyphScreenMetrics.width;
1312 UInt32 height = glyphScreenMetrics.height;
1313 Int32 horiBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
1314 Int32 horiBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
1315 if (horizontal == true)
1317 xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x) - (layoutRecord.realPos & 0xffff0000);
1318 yPos = FloatToFixed(glyphScreenMetrics.topLeft.y);
1321 // Determine vertical glyph metrics
1322 result = ATSUGlyphGetScreenMetrics(_vertFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
1323 if (result != noErr)
1324 return _emptyGlyph;
1325 Real32 vertAdvance = glyphScreenMetrics.deviceAdvance.y;
1326 Int32 vertBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
1327 Int32 vertBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
1328 if (horizontal == false)
1330 xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x);
1331 yPos = FloatToFixed(glyphScreenMetrics.topLeft.y) - ((layoutRecord.realPos + fixed1) & 0xffff0000);
1334 UInt8 *pixmap = 0;
1335 UInt32 size = width * height;
1336 if (size != 0)
1338 // Create pixmap
1339 ATSUTextLayout textLayout = horizontal == true ? _horiTextLayout : _vertTextLayout;
1340 pixmap = new UInt8[size];
1341 drawGlyph(textLayout, layoutRecord, xPos, yPos, width, height, pixmap, 0);
1344 unique_ptr<TextPixmapGlyph> glyph(new TextMacPixmapGlyph(glyphID, width, height, horiAdvance, horiBearingX, horiBearingY, vertAdvance, vertBearingX, vertBearingY, pixmap));
1346 // Put the glyph into the glyph cache
1347 _glyphMap.insert(GlyphMap::value_type(glyphID, glyph.get()));
1349 // Return the glyph
1350 return *(glyph.release());
1354 //----------------------------------------------------------------------
1355 // Constructor
1356 // Author: pdaehne
1357 //----------------------------------------------------------------------
1358 TextMacPixmapGlyph::TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
1359 Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
1360 Real32 vertAdvance, Int32 vertBearingX, Int32 vertBearingY,
1361 UInt8 *pixmap)
1362 : TextPixmapGlyph()
1364 _glyphIndex = glyphIndex;
1365 _width = _pitch = width;
1366 _height = height;
1367 _pixmap = pixmap;
1369 // Determine horizontal glyph metrics
1370 _horiAdvance = horiAdvance;
1371 _horiBearingX = horiBearingX;
1372 _horiBearingY = horiBearingY;
1374 // Determine vertical glyph metrics
1375 _vertAdvance = vertAdvance;
1376 _vertBearingX = vertBearingX;
1377 _vertBearingY = vertBearingY;
1381 //----------------------------------------------------------------------
1382 // Destructor
1383 // Author: pdaehne
1384 //----------------------------------------------------------------------
1385 TextMacPixmapGlyph::~TextMacPixmapGlyph() {}
1388 //----------------------------------------------------------------------
1389 // Constructor
1390 // Author: pdaehne
1391 //----------------------------------------------------------------------
1392 TextMacTXFFace::TextMacTXFFace(ATSUStyle horiFontStyle, const TextTXFParam &param)
1393 : TextTXFFace()
1395 // Create all ATSU objects
1396 ATSUStyle vertFontStyle;
1397 ATSUTextLayout horiTextLayout, vertTextLayout;
1398 createATSUObjects(horiFontStyle, vertFontStyle, horiTextLayout, vertTextLayout);
1400 // Try to get information about the face
1401 getFaceInfo(horiFontStyle, vertFontStyle, _family, _style,
1402 _horiAscent, _horiDescent, _vertAscent, _vertDescent);
1404 // Determine the scale factor
1405 _scale = 1.f / (_horiAscent - _horiDescent);
1407 // Determine ascent
1408 _horiAscent *= _scale;
1409 _vertAscent = -0.5f;
1411 // Determine descent
1412 _horiDescent *= _scale;
1413 _vertDescent = 0.5f;
1415 // Set the parameters
1416 _param = param;
1418 // Switch off all font features
1419 ATSUFontFeatureType featureType = kAllTypographicFeaturesType;
1420 ATSUFontFeatureSelector featureSelector = kAllTypeFeaturesOffSelector;
1421 ATSUSetFontFeatures(horiFontStyle, 1, &featureType, &featureSelector);
1422 ATSUSetFontFeatures(vertFontStyle, 1, &featureType, &featureSelector);
1424 // Create all glyphs and the texture
1425 createGlyphs(horiFontStyle, vertFontStyle, horiTextLayout, vertTextLayout, param);
1427 // Dispose the layout objects
1428 ATSUDisposeTextLayout(horiTextLayout);
1429 ATSUDisposeTextLayout(vertTextLayout);
1431 // Dispose style objects
1432 ATSUDisposeStyle(horiFontStyle);
1433 ATSUDisposeStyle(vertFontStyle);
1437 //----------------------------------------------------------------------
1438 // Destructor
1439 // Author: pdaehne
1440 //----------------------------------------------------------------------
1441 TextMacTXFFace::~TextMacTXFFace() {}
1444 //----------------------------------------------------------------------
1445 // Creates all glyphs and the texture
1446 // Author: pdaehne
1447 //----------------------------------------------------------------------
1448 void TextMacTXFFace::createGlyphs(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle,
1449 ATSUTextLayout horiTextLayout, ATSUTextLayout vertTextLayout,
1450 const TextTXFParam &param)
1452 // Convert the unicode character string to utf16
1453 vector<UniChar> utf16Characters;
1454 convertUnicodeToUTF16(param.getCharacters(), utf16Characters);
1456 // Set the character string
1457 OSStatus result = ATSUSetTextPointerLocation(horiTextLayout, &(utf16Characters[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Characters.size());
1458 if (result != noErr)
1459 return;
1461 // Set the style object
1462 result = ATSUSetRunStyle(horiTextLayout, horiFontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
1463 if (result != noErr)
1464 return;
1466 // Get the layout records
1467 ATSLayoutRecord *layoutRecords;
1468 ItemCount numRecords;
1469 result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(horiTextLayout, kATSUFromTextBeginning,
1470 kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
1471 if (result != noErr)
1472 return;
1474 // Determine horizontal glyph metrics
1475 vector<ATSGlyphScreenMetrics> horiMetrics;
1476 horiMetrics.resize(numRecords);
1477 result = ATSUGlyphGetScreenMetrics(horiFontStyle, numRecords, &(layoutRecords[0].glyphID), sizeof(ATSLayoutRecord), true, true, &(horiMetrics.front()));
1478 if (result != noErr)
1480 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
1481 return;
1484 // Determine vertical glyph metrics
1485 vector<ATSGlyphScreenMetrics> vertMetrics;
1486 vertMetrics.resize(numRecords);
1487 result = ATSUGlyphGetScreenMetrics(vertFontStyle, numRecords, &(layoutRecords[0].glyphID), sizeof(ATSLayoutRecord), true, true, &(vertMetrics.front()));
1488 if (result != noErr)
1490 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
1491 return;
1494 // Create all glyphs
1495 OSG_ASSERT(numRecords == param.getCharacters().length() + 1);
1496 ItemCount j;
1497 for (j = 0; j < numRecords - 1; ++j)
1499 ATSGlyphRef glyphID = layoutRecords[j].glyphID;
1500 wchar_t c = param.getCharacters()[j];
1501 _glyphMap.insert(GlyphMap::value_type(c, new TextMacTXFGlyph(c, _scale, horiMetrics[j], vertMetrics[j])));
1504 // Calculate the positions of the glyphs on the texture
1505 prepareTexture(param);
1506 OSG_ASSERT(_texture != NULL);
1507 OSG_ASSERT(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
1509 // Create the texture
1510 for (j = 0; j < numRecords - 1; ++j)
1512 wchar_t c = param.getCharacters()[j];
1513 TextTXFGlyph *glyph = _glyphMap[c];
1515 // Create pixmap
1516 ATSUTextMeasurement xPos = FloatToFixed(-horiMetrics[j].topLeft.x) - (layoutRecords[j].realPos & 0xffff0000);
1517 ATSUTextMeasurement yPos = FloatToFixed(horiMetrics[j].topLeft.y);
1518 UInt32 width = glyph->getPixmapWidth();
1519 UInt32 height = glyph->getPixmapHeight();
1520 UInt8 *dst = _texture->editData() + glyph->getX() + glyph->getY() * _texture->getWidth();
1521 UInt32 pitch = _texture->getWidth() - width;
1522 drawGlyph(horiTextLayout, layoutRecords[j], xPos, yPos, width, height, dst, pitch);
1525 // Cleanup
1526 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
1530 //----------------------------------------------------------------------
1531 // Constructor
1532 // Author: pdaehne
1533 //----------------------------------------------------------------------
1534 TextMacTXFGlyph::TextMacTXFGlyph(Index glyphIndex, Real32 scale, const ATSGlyphScreenMetrics &horiMetrics, const ATSGlyphScreenMetrics &vertMetrics)
1535 : TextTXFGlyph()
1537 _glyphIndex = glyphIndex;
1538 _scale = scale;
1539 _width = horiMetrics.width;
1540 _height = horiMetrics.height;
1542 // Determine horizontal glyph metrics
1543 _horiAdvance = horiMetrics.deviceAdvance.x * _scale;
1544 _horiBearingX = static_cast<int>(horiMetrics.topLeft.x);
1545 _horiBearingY = static_cast<int>(horiMetrics.topLeft.y);
1547 // Determine vertical glyph metrics
1548 _vertAdvance = vertMetrics.deviceAdvance.y * _scale;
1549 _vertBearingX = static_cast<int>(vertMetrics.topLeft.x);
1550 _vertBearingY = static_cast<int>(vertMetrics.topLeft.y);
1554 //----------------------------------------------------------------------
1555 // Destructor
1556 // Author: pdaehne
1557 //----------------------------------------------------------------------
1558 TextMacTXFGlyph::~TextMacTXFGlyph() {}
1561 OSG_END_NAMESPACE
1564 #endif // defined(__APPLE__) && !defined(__LP64__)