1 /*---------------------------------------------------------------------------*\
5 * Copyright(C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
41 # pragma warning (disable: 4786)
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"
63 #include <ApplicationServices/ApplicationServices.h>
68 //----------------------------------------------------------------------
69 // MacOS X specific implementation of the TextVectorFace class
71 //----------------------------------------------------------------------
76 class TextMacVectorFace
: public TextVectorFace
81 TextMacVectorFace(ATSUStyle horiFontStyle
);
84 virtual ~TextMacVectorFace();
86 // Lays out one line of text
87 virtual void layout(const wstring
&text
, const TextLayoutParam
¶m
,
88 TextLayoutResult
&layoutResult
);
92 // Creates a new Glyph object
93 virtual unique_ptr
<TextVectorGlyph
> createGlyph(TextGlyph::Index glyphIndex
);
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
110 //----------------------------------------------------------------------
115 class TextMacVectorGlyph
: public TextVectorGlyph
120 TextMacVectorGlyph(Index glyphIndex
, Real32 scale
, ATSUStyle horiFontStyle
, ATSUStyle vertFontStyle
);
123 virtual ~TextMacVectorGlyph();
127 //----------------------------------------------------------------------
128 // MacOS X specific implementation of the TextPixmapFace class
130 //----------------------------------------------------------------------
135 class TextMacPixmapFace
: public TextPixmapFace
140 TextMacPixmapFace(ATSUStyle horiFontStyle
);
143 virtual ~TextMacPixmapFace();
145 // Lays out one line of text
146 virtual void layout(const wstring
&text
, const TextLayoutParam
¶m
,
147 TextLayoutResult
&layoutResult
);
151 // Creates a new Glyph object
152 virtual unique_ptr
<TextPixmapGlyph
> createGlyph(TextGlyph::Index glyphIndex
);
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
171 //----------------------------------------------------------------------
176 class TextMacPixmapGlyph
: public TextPixmapGlyph
181 TextMacPixmapGlyph(Index glyphIndex
, UInt32 width
, UInt32 height
,
182 Real32 horiAdvance
, Int32 horiBearingX
, Int32 horiBearingY
,
183 Real32 vertAdvance
, Int32 vertBearingX
, Int32 vertBearingY
,
187 virtual ~TextMacPixmapGlyph();
191 //----------------------------------------------------------------------
192 // MacOS X specific implementation of the TextTXFFace class
194 //----------------------------------------------------------------------
199 class TextMacTXFFace
: public TextTXFFace
204 TextMacTXFFace(ATSUStyle horiFontStyle
, const TextTXFParam
¶m
);
207 virtual ~TextMacTXFFace();
211 void createGlyphs(ATSUStyle horiFontStyle
, ATSUStyle vertFontStyle
,
212 ATSUTextLayout horiTextLayout
, ATSUTextLayout vertTextLayout
,
213 const TextTXFParam
¶m
);
217 //----------------------------------------------------------------------
218 // MacOS X specific implementation of the TextTXFGlyph class
220 //----------------------------------------------------------------------
225 class TextMacTXFGlyph
: public TextTXFGlyph
230 TextMacTXFGlyph(Index glyphIndex
, Real32 scale
, const ATSGlyphScreenMetrics
&horiMetrics
, const ATSGlyphScreenMetrics
&vertMetrics
);
233 virtual ~TextMacTXFGlyph();
237 //----------------------------------------------------------------------
240 //----------------------------------------------------------------------
241 TextMacBackend::TextMacBackend(): TextBackend() {}
244 //----------------------------------------------------------------------
247 //----------------------------------------------------------------------
248 TextMacBackend::~TextMacBackend() {}
251 //----------------------------------------------------------------------
252 // Returns the family name of a font
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
);
263 ByteCount actualNameLength
;
264 result
= ATSUGetIndFontName(fontID
, fontNameIndex
, 0, 0, &actualNameLength
,
266 if ((result
!= noErr
) || (actualNameLength
== 0))
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))
276 switch (fontNamePlatform
)
278 case kFontUnicodePlatform
:
279 case kFontMicrosoftPlatform
: // ???
280 str
= CFStringCreateWithBytes(kCFAllocatorDefault
, reinterpret_cast< ::UInt8
*>(&(name
.front())),
281 actualNameLength
, kCFStringEncodingUnicode
, false);
283 case kFontMacintoshPlatform
:
284 str
= CFStringCreateWithBytes(kCFAllocatorDefault
, reinterpret_cast< ::UInt8
*>(&(name
.front())),
285 actualNameLength
, kCFStringEncodingMacRoman
, false);
292 CFDataRef data
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, str
, kCFStringEncodingUTF8
, ' ');
296 string
familyName(reinterpret_cast<const char*>(CFDataGetBytePtr(data
)),
297 static_cast<string::size_type
>(CFDataGetLength(data
)));
303 //----------------------------------------------------------------------
304 // Tries to find a font
306 //----------------------------------------------------------------------
307 static ATSUStyle
findFont(const string
&family
, TextFace::Style style
, UInt32 size
)
309 // Handle generic family names
311 if (family
== "SERIF")
312 f
= "Times New Roman";
313 else if (family
== "SANS")
315 else if (family
== "TYPEWRITER")
320 // Get the number of fonts installed
322 OSStatus result
= ATSUFontCount(&fontCount
);
323 if ((result
!= noErr
) || (fontCount
== 0))
326 // Get the IDs of all fonts
327 vector
<ATSUFontID
> fontIDs
;
328 fontIDs
.resize(fontCount
);
329 result
= ATSUGetFontIDs(&(fontIDs
.front()), fontCount
, &fontCount
);
333 // Try to find the font
335 for (i
= 0; i
< fontCount
; ++i
)
337 string familyName
= getFamilyName(fontIDs
[i
]);
343 ATSUFontID fontID
= fontIDs
[i
];
345 FMFontFamily fontFamily
;
346 result
= FMGetFontFamilyInstanceFromFont(fontID
, &fontFamily
, 0);
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
))
364 // Create style object
366 result
= ATSUCreateStyle(&fontStyle
);
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
);
380 ATSUDisposeStyle(fontStyle
);
388 //----------------------------------------------------------------------
389 // Creates a new vector face
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
);
417 //----------------------------------------------------------------------
418 // Creates a new pixmap face
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
);
437 //----------------------------------------------------------------------
438 // Creates a new TXF face
440 //----------------------------------------------------------------------
441 TextTXFFaceTransitPtr
TextMacBackend::createTXFFace(
442 const string
&family
, TextFace::Style style
, const TextTXFParam
¶m
)
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
);
458 //----------------------------------------------------------------------
459 // Returns the names of all font families available
461 //----------------------------------------------------------------------
462 void TextMacBackend::getFontFamilies(vector
<string
> &families
)
466 // Get the number of fonts installed
468 OSStatus result
= ATSUFontCount(&fontCount
);
469 if ((result
!= noErr
) || (fontCount
== 0))
472 // Get the IDs of all fonts
473 vector
<ATSUFontID
> fontIDs
;
474 fontIDs
.resize(fontCount
);
475 result
= ATSUGetFontIDs(&(fontIDs
.front()), fontCount
, &fontCount
);
479 // Put all font families into the vector
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
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
502 OSStatus result
= ATSUGetAttribute(horiFontStyle
, kATSUFontTag
, sizeof(fontID
), &fontID
, 0);
503 if (((result
== noErr
) || (result
== kATSUNotSetErr
)) && (fontID
!= kATSUInvalidFontID
))
504 family
= getFamilyName(fontID
);
510 result
= ATSUGetAttribute(horiFontStyle
, kATSUQDBoldfaceTag
, sizeof(bold
), &bold
, 0);
511 if ((result
!= noErr
) && (result
!= kATSUNotSetErr
))
514 result
= ATSUGetAttribute(horiFontStyle
, kATSUQDItalicTag
, sizeof(italic
), &italic
, 0);
515 if ((result
!= noErr
) && (result
!= kATSUNotSetErr
))
517 style
= (bold
== TRUE
) ?
518 (italic
== TRUE
? TextFace::STYLE_BOLDITALIC
: TextFace::STYLE_BOLD
) :
519 (italic
== TRUE
? TextFace::STYLE_ITALIC
: TextFace::STYLE_PLAIN
);
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
539 //----------------------------------------------------------------------
540 static void createATSUObjects(ATSUStyle horiFontStyle
, ATSUStyle
&vertFontStyle
, ATSUTextLayout
&horiTextLayout
, ATSUTextLayout
&vertTextLayout
)
542 // Create vertical style object
543 OSStatus result
= ATSUCreateAndCopyStyle(horiFontStyle
, &vertFontStyle
);
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
);
559 result
= ATSUCreateAndCopyTextLayout(horiTextLayout
, &vertTextLayout
);
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 //----------------------------------------------------------------------
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
);
591 _horiAscent
*= _scale
;
595 _horiDescent
*= _scale
;
600 //----------------------------------------------------------------------
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
620 //----------------------------------------------------------------------
621 static void convertUnicodeToUTF16(const wstring
&text
, vector
<UniChar
> &utf16Text
)
623 UniCharCount i
, textTotalLength
= text
.length();
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
644 //----------------------------------------------------------------------
645 void TextMacVectorFace::layout(const wstring
&text
, const TextLayoutParam
¶m
,
646 TextLayoutResult
&layoutResult
)
648 // Initialize return values
649 layoutResult
.clear();
650 if (param
.horizontal
== true)
651 layoutResult
.textBounds
[1] = _horiAscent
- _horiDescent
;
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)
662 // Check whether we have to use the horizontal or vertical ATSUI objects
664 ATSUTextLayout textLayout
;
665 if (param
.horizontal
== true)
667 fontStyle
= _horiFontStyle
;
668 textLayout
= _horiTextLayout
;
672 fontStyle
= _vertFontStyle
;
673 textLayout
= _vertTextLayout
;
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
);
686 OSStatus result
= ATSUSetTextPointerLocation(textLayout
, &(utf16Text
[0]), kATSUFromTextBeginning
, kATSUToTextEnd
, utf16Text
.size());
690 // Set the style object
691 result
= ATSUSetRunStyle(textLayout
, fontStyle
, kATSUFromTextBeginning
, kATSUToTextEnd
);
695 // Get the layout records
696 ATSLayoutRecord
*layoutRecords
;
697 ItemCount numRecords
;
698 result
= ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout
, kATSUFromTextBeginning
,
699 kATSUDirectDataLayoutRecordATSLayoutRecordCurrent
, (void**)&layoutRecords
, &numRecords
);
703 ItemCount numDeltaYs
;
704 result
= ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout
, kATSUFromTextBeginning
,
705 kATSUDirectDataBaselineDeltaFixedArray
, (void**)&deltaYs
, &numDeltaYs
);
709 // Calculate the positions of the glyphs
710 layoutResult
.indices
.reserve(numRecords
);
711 layoutResult
.positions
.reserve(numRecords
);
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();
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
);
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());
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
759 //----------------------------------------------------------------------
760 typedef struct UserData
764 TextVectorGlyph::Outline
&outline
;
765 inline UserData(Real32 s
, const Vec2f
&off
, TextVectorGlyph::Outline
&o
)
766 : scale(s
), offset(off
), outline(o
)
772 //----------------------------------------------------------------------
773 // callback function that starts a new contour
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());
788 //----------------------------------------------------------------------
789 // callback function that adds a line to the contour
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
));
816 //----------------------------------------------------------------------
817 // callback function that adds a quadratic Bezier spline to the contour
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
));
848 //----------------------------------------------------------------------
849 // callback function that closes a contour
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);
866 //----------------------------------------------------------------------
867 // callback function that starts a new contour
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
));
888 //----------------------------------------------------------------------
889 // callback function that adds a line to the contour
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
));
907 //----------------------------------------------------------------------
908 // callback function that adds a cubic Bezier spline to the contour
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
));
934 //----------------------------------------------------------------------
935 // callback function that closes a contour
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);
952 //----------------------------------------------------------------------
953 // Creates a new Glyph object
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 //----------------------------------------------------------------------
970 //----------------------------------------------------------------------
971 TextMacVectorGlyph::TextMacVectorGlyph(Index glyphIndex
, Real32 scale
, ATSUStyle horiFontStyle
, ATSUStyle vertFontStyle
)
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
);
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
);
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
;
1001 ATSCurveType curveType
;
1002 result
= ATSUGetNativeCurveType(horiFontStyle
, &curveType
);
1003 if (result
!= noErr
)
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 //----------------------------------------------------------------------
1043 //----------------------------------------------------------------------
1044 TextMacVectorGlyph::~TextMacVectorGlyph() {}
1047 //----------------------------------------------------------------------
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
1063 OSStatus result
= ATSUGetAttribute(_horiFontStyle
, kATSUSizeTag
, sizeof(size
), &size
, 0);
1064 _size
= ((result
== noErr
) || (result
== kATSUNotSetErr
)) ? FixedToInt(size
) : 0;
1068 //----------------------------------------------------------------------
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
1087 //----------------------------------------------------------------------
1088 void TextMacPixmapFace::layout(const wstring
&text
, const TextLayoutParam
¶m
,
1089 TextLayoutResult
&layoutResult
)
1091 // Initialize return values
1092 layoutResult
.clear();
1093 if (param
.horizontal
== true)
1094 layoutResult
.textBounds
[1] = _horiAscent
- _horiDescent
;
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)
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
;
1115 fontStyle
= _vertFontStyle
;
1116 textLayout
= _vertTextLayout
;
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
);
1129 OSStatus result
= ATSUSetTextPointerLocation(textLayout
, &(utf16Text
[0]), kATSUFromTextBeginning
, kATSUToTextEnd
, utf16Text
.size());
1130 if (result
!= noErr
)
1133 // Set the style object
1134 result
= ATSUSetRunStyle(textLayout
, fontStyle
, kATSUFromTextBeginning
, kATSUToTextEnd
);
1135 if (result
!= noErr
)
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
)
1146 ItemCount numDeltaYs
;
1147 result
= ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout
, kATSUFromTextBeginning
,
1148 kATSUDirectDataBaselineDeltaFixedArray
, (void**)&deltaYs
, &numDeltaYs
);
1149 if (result
!= noErr
)
1152 // Calculate the positions of the glyphs
1153 layoutResult
.indices
.reserve(numRecords
);
1154 layoutResult
.positions
.reserve(numRecords
);
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();
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
);
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());
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
1202 //----------------------------------------------------------------------
1203 unique_ptr
<TextPixmapGlyph
> TextMacPixmapFace::createGlyph(TextGlyph::Index glyphIndex
)
1205 return unique_ptr
<TextPixmapGlyph
>();
1209 //----------------------------------------------------------------------
1210 // Renders a glyph into a memory buffer
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))
1221 // Create offscreen GWorld
1222 GWorldPtr offscreenGWorld
;
1224 SetRect(&boundsRect
, 0, 0, width
, height
);
1225 QDErr qdResult
= NewGWorld(&offscreenGWorld
, 32, &boundsRect
, 0, 0, 0);
1226 if (qdResult
!= noErr
)
1229 // Get the pixel buffer of the offscreen GWorld
1230 if (LockPixels(GetGWorldPixMap(offscreenGWorld
)) == FALSE
)
1232 DisposeGWorld(offscreenGWorld
);
1235 Ptr src
= GetPixBaseAddr(GetGWorldPixMap(offscreenGWorld
));
1238 UnlockPixels(GetGWorldPixMap(offscreenGWorld
));
1239 DisposeGWorld(offscreenGWorld
);
1243 // Initialize and activate the offscreen GWorld
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
);
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);
1264 for (y
= 0; y
< height
; ++y
)
1267 for (x
= 0; x
< width
; ++x
)
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.
1287 //----------------------------------------------------------------------
1288 const TextPixmapGlyph
&TextMacPixmapFace::getPixmapGlyph(const ATSLayoutRecord
&layoutRecord
, bool horizontal
)
1290 ATSGlyphRef glyphID
= layoutRecord
.glyphID
;
1291 if (glyphID
== kATSDeletedGlyphcode
)
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
)
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
)
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);
1335 UInt32 size
= width
* height
;
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()));
1350 return *(glyph
.release());
1354 //----------------------------------------------------------------------
1357 //----------------------------------------------------------------------
1358 TextMacPixmapGlyph::TextMacPixmapGlyph(Index glyphIndex
, UInt32 width
, UInt32 height
,
1359 Real32 horiAdvance
, Int32 horiBearingX
, Int32 horiBearingY
,
1360 Real32 vertAdvance
, Int32 vertBearingX
, Int32 vertBearingY
,
1364 _glyphIndex
= glyphIndex
;
1365 _width
= _pitch
= width
;
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 //----------------------------------------------------------------------
1384 //----------------------------------------------------------------------
1385 TextMacPixmapGlyph::~TextMacPixmapGlyph() {}
1388 //----------------------------------------------------------------------
1391 //----------------------------------------------------------------------
1392 TextMacTXFFace::TextMacTXFFace(ATSUStyle horiFontStyle
, const TextTXFParam
¶m
)
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
);
1408 _horiAscent
*= _scale
;
1409 _vertAscent
= -0.5f
;
1411 // Determine descent
1412 _horiDescent
*= _scale
;
1413 _vertDescent
= 0.5f
;
1415 // Set the parameters
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 //----------------------------------------------------------------------
1440 //----------------------------------------------------------------------
1441 TextMacTXFFace::~TextMacTXFFace() {}
1444 //----------------------------------------------------------------------
1445 // Creates all glyphs and the texture
1447 //----------------------------------------------------------------------
1448 void TextMacTXFFace::createGlyphs(ATSUStyle horiFontStyle
, ATSUStyle vertFontStyle
,
1449 ATSUTextLayout horiTextLayout
, ATSUTextLayout vertTextLayout
,
1450 const TextTXFParam
¶m
)
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
)
1461 // Set the style object
1462 result
= ATSUSetRunStyle(horiTextLayout
, horiFontStyle
, kATSUFromTextBeginning
, kATSUToTextEnd
);
1463 if (result
!= noErr
)
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
)
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
);
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
);
1494 // Create all glyphs
1495 OSG_ASSERT(numRecords
== param
.getCharacters().length() + 1);
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
];
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
);
1526 ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent
, (void**)&layoutRecords
);
1530 //----------------------------------------------------------------------
1533 //----------------------------------------------------------------------
1534 TextMacTXFGlyph::TextMacTXFGlyph(Index glyphIndex
, Real32 scale
, const ATSGlyphScreenMetrics
&horiMetrics
, const ATSGlyphScreenMetrics
&vertMetrics
)
1537 _glyphIndex
= glyphIndex
;
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 //----------------------------------------------------------------------
1557 //----------------------------------------------------------------------
1558 TextMacTXFGlyph::~TextMacTXFGlyph() {}
1564 #endif // defined(__APPLE__) && !defined(__LP64__)