PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/System/Text/OSGTextMacBackend.cpp

https://github.com/danguilliams/OpenSGDevMaster_Toolbox
C++ | 1541 lines | 938 code | 238 blank | 365 comment | 217 complexity | 3bd1307f3ca2e498bc42c6917cb99569 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  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. \*---------------------------------------------------------------------------*/
  38. #ifdef _MSC_VER
  39. # pragma warning (disable: 4786)
  40. #endif
  41. #include "OSGTextMacBackend.h"
  42. #include "OSGBaseTypes.h"
  43. #ifdef __APPLE__
  44. #include "OSGTextPixmapFace.h"
  45. #include "OSGTextPixmapGlyph.h"
  46. #include "OSGTextVectorFace.h"
  47. #include "OSGTextVectorGlyph.h"
  48. #include "OSGTextTXFFace.h"
  49. #include "OSGTextTXFGlyph.h"
  50. #include "OSGTextLayoutParam.h"
  51. #include "OSGTextLayoutResult.h"
  52. #include <iostream>
  53. #include <algorithm>
  54. #include <set>
  55. #include <ApplicationServices/ApplicationServices.h>
  56. using namespace std;
  57. OSG_BEGIN_NAMESPACE
  58. //----------------------------------------------------------------------
  59. // MacOS X specific implementation of the TextVectorFace class
  60. // Author: pdaehne
  61. //----------------------------------------------------------------------
  62. class TextMacVectorFace: public TextVectorFace
  63. {
  64. public:
  65. // Constructor
  66. TextMacVectorFace(ATSUStyle horiFontStyle);
  67. // Destructor
  68. virtual ~TextMacVectorFace();
  69. // Lays out one line of text
  70. virtual void layout(const wstring &text, const TextLayoutParam &param,
  71. TextLayoutResult &layoutResult);
  72. protected:
  73. // Creates a new Glyph object
  74. virtual auto_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
  75. private:
  76. // The style objects that define the font
  77. ATSUStyle _horiFontStyle;
  78. ATSUStyle _vertFontStyle;
  79. // The layout objects that handle the text layout
  80. ATSUTextLayout _horiTextLayout;
  81. ATSUTextLayout _vertTextLayout;
  82. };
  83. //----------------------------------------------------------------------
  84. // MacOS X specific implementation of the TextVectorGlyph class
  85. // Author: pdaehne
  86. //----------------------------------------------------------------------
  87. class TextMacVectorGlyph: public TextVectorGlyph
  88. {
  89. public:
  90. // Constructor
  91. TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle);
  92. // Destructor
  93. virtual ~TextMacVectorGlyph();
  94. };
  95. //----------------------------------------------------------------------
  96. // MacOS X specific implementation of the TextPixmapFace class
  97. // Author: pdaehne
  98. //----------------------------------------------------------------------
  99. class TextMacPixmapFace: public TextPixmapFace
  100. {
  101. public:
  102. // Constructor
  103. TextMacPixmapFace(ATSUStyle horiFontStyle);
  104. // Destructor
  105. virtual ~TextMacPixmapFace();
  106. // Lays out one line of text
  107. virtual void layout(const wstring &text, const TextLayoutParam &param,
  108. TextLayoutResult &layoutResult);
  109. protected:
  110. // Creates a new Glyph object
  111. virtual auto_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
  112. private:
  113. const TextPixmapGlyph &getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal);
  114. // The style objects that define the font
  115. ATSUStyle _horiFontStyle;
  116. ATSUStyle _vertFontStyle;
  117. // The layout objects that handle the text layout
  118. ATSUTextLayout _horiTextLayout;
  119. ATSUTextLayout _vertTextLayout;
  120. };
  121. //----------------------------------------------------------------------
  122. // MacOS X specific implementation of the TextPixmapGlyph class
  123. // Author: pdaehne
  124. //----------------------------------------------------------------------
  125. class TextMacPixmapGlyph: public TextPixmapGlyph
  126. {
  127. public:
  128. // Constructor
  129. TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
  130. Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
  131. Real32 vertAdvance, Int32 vertBearingX, Int32 vertBearingY,
  132. UInt8 *pixmap);
  133. // Destructor
  134. virtual ~TextMacPixmapGlyph();
  135. };
  136. //----------------------------------------------------------------------
  137. // MacOS X specific implementation of the TextTXFFace class
  138. // Author: pdaehne
  139. //----------------------------------------------------------------------
  140. class TextMacTXFFace: public TextTXFFace
  141. {
  142. public:
  143. // Constructor
  144. TextMacTXFFace(ATSUStyle horiFontStyle, const TextTXFParam &param);
  145. // Destructor
  146. virtual ~TextMacTXFFace();
  147. private:
  148. void createGlyphs(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle,
  149. ATSUTextLayout horiTextLayout, ATSUTextLayout vertTextLayout,
  150. const TextTXFParam &param);
  151. };
  152. //----------------------------------------------------------------------
  153. // MacOS X specific implementation of the TextTXFGlyph class
  154. // Author: pdaehne
  155. //----------------------------------------------------------------------
  156. class TextMacTXFGlyph: public TextTXFGlyph
  157. {
  158. public:
  159. // Constructor
  160. TextMacTXFGlyph(Index glyphIndex, Real32 scale, const ATSGlyphScreenMetrics &horiMetrics, const ATSGlyphScreenMetrics &vertMetrics);
  161. // Destructor
  162. virtual ~TextMacTXFGlyph();
  163. };
  164. //----------------------------------------------------------------------
  165. // Constructor
  166. // Author: pdaehne
  167. //----------------------------------------------------------------------
  168. TextMacBackend::TextMacBackend(): TextBackend() {}
  169. //----------------------------------------------------------------------
  170. // Destructor
  171. // Author: pdaehne
  172. //----------------------------------------------------------------------
  173. TextMacBackend::~TextMacBackend() {}
  174. //----------------------------------------------------------------------
  175. // Returns the family name of a font
  176. // Author: pdaehne
  177. //----------------------------------------------------------------------
  178. static string getFamilyName(ATSUFontID fontID)
  179. {
  180. ItemCount fontNameIndex;
  181. OSStatus result = ATSUFindFontName(fontID, kFontFamilyName, kFontNoPlatformCode,
  182. kFontNoScriptCode, kFontNoLanguageCode,
  183. 0, 0, 0, &fontNameIndex);
  184. if (result != noErr)
  185. return string();
  186. ByteCount actualNameLength;
  187. result = ATSUGetIndFontName(fontID, fontNameIndex, 0, 0, &actualNameLength,
  188. 0, 0, 0, 0);
  189. if ((result != noErr) || (actualNameLength == 0))
  190. return string();
  191. vector<char> name;
  192. name.resize(actualNameLength);
  193. FontPlatformCode fontNamePlatform;
  194. result = ATSUGetIndFontName(fontID, fontNameIndex, actualNameLength, &(name.front()), 0,
  195. 0, &fontNamePlatform, 0, 0);
  196. if ((result != noErr) || (actualNameLength == 0))
  197. return string();
  198. CFStringRef str = 0;
  199. switch (fontNamePlatform)
  200. {
  201. case kFontUnicodePlatform:
  202. case kFontMicrosoftPlatform: // ???
  203. str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
  204. actualNameLength, kCFStringEncodingUnicode, false);
  205. break;
  206. case kFontMacintoshPlatform:
  207. str = CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast< ::UInt8*>(&(name.front())),
  208. actualNameLength, kCFStringEncodingMacRoman, false);
  209. break;
  210. default:
  211. return string();
  212. }
  213. if (str == 0)
  214. return string();
  215. CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, ' ');
  216. CFRelease(str);
  217. if (data == 0)
  218. return string();
  219. string familyName(reinterpret_cast<const char*>(CFDataGetBytePtr(data)),
  220. static_cast<string::size_type>(CFDataGetLength(data)));
  221. CFRelease(data);
  222. return familyName;
  223. }
  224. //----------------------------------------------------------------------
  225. // Tries to find a font
  226. // Author: pdaehne
  227. //----------------------------------------------------------------------
  228. static ATSUStyle findFont(const string &family, TextFace::Style style, UInt32 size)
  229. {
  230. // Handle generic family names
  231. string f;
  232. if (family == "SERIF")
  233. f = "Times New Roman";
  234. else if (family == "SANS")
  235. f = "Arial";
  236. else if (family == "TYPEWRITER")
  237. f = "Courier";
  238. else
  239. f = family;
  240. // Get the number of fonts installed
  241. ItemCount fontCount;
  242. OSStatus result = ATSUFontCount(&fontCount);
  243. if ((result != noErr) || (fontCount == 0))
  244. return 0;
  245. // Get the IDs of all fonts
  246. vector<ATSUFontID> fontIDs;
  247. fontIDs.resize(fontCount);
  248. result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
  249. if (result != noErr)
  250. return 0;
  251. // Try to find the font
  252. ItemCount i;
  253. for (i = 0; i < fontCount; ++i)
  254. {
  255. string familyName = getFamilyName(fontIDs[i]);
  256. if (familyName == f)
  257. break;
  258. }
  259. if (i >= fontCount)
  260. return 0;
  261. ATSUFontID fontID = fontIDs[i];
  262. FMFontFamily fontFamily;
  263. result = FMGetFontFamilyInstanceFromFont(fontID, &fontFamily, 0);
  264. if (result != noErr)
  265. return 0;
  266. FMFontStyle fStyle;
  267. switch (style)
  268. {
  269. default:
  270. FWARNING(("Invalid font style parameter.\n"));
  271. // intentionally fall through
  272. case TextFace::STYLE_PLAIN: fStyle = normal; break;
  273. case TextFace::STYLE_BOLD: fStyle = bold; break;
  274. case TextFace::STYLE_ITALIC: fStyle = italic; break;
  275. case TextFace::STYLE_BOLDITALIC: fStyle = bold | italic; break;
  276. }
  277. result = FMGetFontFromFontFamilyInstance(fontFamily, fStyle, &fontID, 0);
  278. if ((result != noErr) || (fontID == kATSUInvalidFontID))
  279. return 0;
  280. // Create style object
  281. ATSUStyle fontStyle;
  282. result = ATSUCreateStyle(&fontStyle);
  283. if (result != noErr)
  284. return 0;
  285. // Set style attributes
  286. //Boolean bold = ((style == TextFace::STYLE_BOLD) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
  287. //Boolean italic = ((style == TextFace::STYLE_ITALIC) || (style == TextFace::STYLE_BOLDITALIC)) ? TRUE : FALSE;
  288. Fixed fontSize = IntToFixed(size);
  289. ATSUAttributeTag attributeTags[] = { kATSUFontTag, /*kATSUQDBoldfaceTag, kATSUQDItalicTag,*/ kATSUSizeTag };
  290. ByteCount attributeSizes[] = { sizeof(fontID), /*sizeof(bold), sizeof(italic),*/ sizeof(fontSize) };
  291. ATSUAttributeValuePtr attributeValues[] = { &fontID, /*&bold, &italic,*/ &fontSize };
  292. result = ATSUSetAttributes(fontStyle, /*4*/2, attributeTags, attributeSizes, attributeValues);
  293. if (result != noErr)
  294. {
  295. ATSUDisposeStyle(fontStyle);
  296. return 0;
  297. }
  298. return fontStyle;
  299. }
  300. //----------------------------------------------------------------------
  301. // Creates a new vector face
  302. // Author: pdaehne
  303. //----------------------------------------------------------------------
  304. TextVectorFaceTransitPtr TextMacBackend::createVectorFace(
  305. const string &family, TextFace::Style style)
  306. {
  307. TextVectorFaceTransitPtr retVal;
  308. // Try to find the font
  309. ATSUStyle horiFontStyle = findFont(family, style, 1000);
  310. if (horiFontStyle != 0)
  311. {
  312. // Switch off hinting
  313. ATSStyleRenderingOptions styleRenderingOptions = kATSStyleNoHinting;
  314. ATSUAttributeTag attributeTag = kATSUStyleRenderingOptionsTag;
  315. ByteCount attributeSize = sizeof(styleRenderingOptions);
  316. ATSUAttributeValuePtr attributeValue = &styleRenderingOptions;
  317. OSStatus result = ATSUSetAttributes(horiFontStyle, 1, &attributeTag, &attributeSize, &attributeValue);
  318. // We don't care for errors - this is not really an important attribute
  319. // Create the new face object
  320. retVal = new TextMacVectorFace(horiFontStyle);
  321. }
  322. return retVal;
  323. }
  324. //----------------------------------------------------------------------
  325. // Creates a new pixmap face
  326. // Author: pdaehne
  327. //----------------------------------------------------------------------
  328. TextPixmapFaceTransitPtr TextMacBackend::createPixmapFace(
  329. const string &family, TextFace::Style style, UInt32 size)
  330. {
  331. TextPixmapFaceTransitPtr retVal;
  332. // Try to find the font
  333. ATSUStyle horiFontStyle = findFont(family, style, size);
  334. if (horiFontStyle != 0)
  335. {
  336. retVal = new TextMacPixmapFace(horiFontStyle);
  337. }
  338. return retVal;
  339. }
  340. //----------------------------------------------------------------------
  341. // Creates a new TXF face
  342. // Author: pdaehne
  343. //----------------------------------------------------------------------
  344. TextTXFFaceTransitPtr TextMacBackend::createTXFFace(
  345. const string &family, TextFace::Style style, const TextTXFParam &param)
  346. {
  347. TextTXFFaceTransitPtr retVal;
  348. // Try to find the font
  349. ATSUStyle horiFontStyle = findFont(family, style, param.size);
  350. if (horiFontStyle != 0)
  351. {
  352. // Create the new face object
  353. retVal = new TextMacTXFFace(horiFontStyle, param);
  354. }
  355. return retVal;
  356. }
  357. //----------------------------------------------------------------------
  358. // Returns the names of all font families available
  359. // Author: pdaehne
  360. //----------------------------------------------------------------------
  361. void TextMacBackend::getFontFamilies(vector<string> &families)
  362. {
  363. families.clear();
  364. // Get the number of fonts installed
  365. ItemCount fontCount;
  366. OSStatus result = ATSUFontCount(&fontCount);
  367. if ((result != noErr) || (fontCount == 0))
  368. return;
  369. // Get the IDs of all fonts
  370. vector<ATSUFontID> fontIDs;
  371. fontIDs.resize(fontCount);
  372. result = ATSUGetFontIDs(&(fontIDs.front()), fontCount, &fontCount);
  373. if (result != noErr)
  374. return;
  375. // Put all font families into the vector
  376. ItemCount i;
  377. set<string> familySet;
  378. for (i = 0; i < fontCount; ++i)
  379. {
  380. string familyName = getFamilyName(fontIDs[i]);
  381. if (familyName.empty() == false)
  382. familySet.insert(familyName);
  383. }
  384. families.assign(familySet.begin(), familySet.end());
  385. }
  386. //----------------------------------------------------------------------
  387. // Tries to get information about the face
  388. // Author: pdaehne
  389. //----------------------------------------------------------------------
  390. static void getFaceInfo(ATSUStyle horiFontStyle, ATSUStyle vertFontStyle, string &family, TextFace::Style &style,
  391. Real32 &horiAscent, Real32 &horiDescent,
  392. Real32 &vertAscent, Real32 &vertDescent)
  393. {
  394. // Try to get the family name
  395. ATSUFontID fontID;
  396. OSStatus result = ATSUGetAttribute(horiFontStyle, kATSUFontTag, sizeof(fontID), &fontID, 0);
  397. if (((result == noErr) || (result == kATSUNotSetErr)) && (fontID != kATSUInvalidFontID))
  398. family = getFamilyName(fontID);
  399. else
  400. family.erase();
  401. // Try to get style
  402. Boolean bold;
  403. result = ATSUGetAttribute(horiFontStyle, kATSUQDBoldfaceTag, sizeof(bold), &bold, 0);
  404. if ((result != noErr) && (result != kATSUNotSetErr))
  405. bold = false;
  406. Boolean italic;
  407. result = ATSUGetAttribute(horiFontStyle, kATSUQDItalicTag, sizeof(italic), &italic, 0);
  408. if ((result != noErr) && (result != kATSUNotSetErr))
  409. italic = false;
  410. style = (bold == TRUE) ?
  411. (italic == TRUE ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD) :
  412. (italic == TRUE ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN);
  413. // Try to get ascent
  414. ATSUTextMeasurement measurement;
  415. result = ATSUGetAttribute(horiFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
  416. horiAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
  417. result = ATSUGetAttribute(vertFontStyle, kATSUAscentTag, sizeof(measurement), &measurement, 0);
  418. vertAscent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
  419. // Try to get descent
  420. result = ATSUGetAttribute(horiFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
  421. horiDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? -FixedToFloat(measurement) : 0.f;
  422. result = ATSUGetAttribute(vertFontStyle, kATSUDescentTag, sizeof(measurement), &measurement, 0);
  423. vertDescent = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToFloat(measurement) : 0.f;
  424. }
  425. //----------------------------------------------------------------------
  426. // Creates all ATSU objects needed by a face
  427. // Author: pdaehne
  428. //----------------------------------------------------------------------
  429. static void createATSUObjects(ATSUStyle horiFontStyle, ATSUStyle &vertFontStyle, ATSUTextLayout &horiTextLayout, ATSUTextLayout &vertTextLayout)
  430. {
  431. // Create vertical style object
  432. OSStatus result = ATSUCreateAndCopyStyle(horiFontStyle, &vertFontStyle);
  433. if (result != noErr)
  434. vertFontStyle = 0;
  435. else
  436. {
  437. ATSUVerticalCharacterType verticalCharacterType = kATSUStronglyVertical;
  438. ATSUAttributeTag attributeTags[] = { kATSUVerticalCharacterTag };
  439. ByteCount attributeSizes[] = { sizeof(verticalCharacterType) };
  440. ATSUAttributeValuePtr attributeValues[] = { &verticalCharacterType };
  441. result = ATSUSetAttributes(vertFontStyle, 1, attributeTags, attributeSizes, attributeValues);
  442. }
  443. // Create the layout objects
  444. result = ATSUCreateTextLayout(&horiTextLayout);
  445. if (result != noErr)
  446. horiTextLayout = 0;
  447. result = ATSUCreateAndCopyTextLayout(horiTextLayout, &vertTextLayout);
  448. if (result != noErr)
  449. vertTextLayout = 0;
  450. else
  451. {
  452. Fixed lineRotation = IntToFixed(-90);
  453. ATSUAttributeTag layoutAttributeTags[] = { kATSULineRotationTag };
  454. ByteCount layoutAttributeSizes[] = { sizeof(lineRotation) };
  455. ATSUAttributeValuePtr layoutAttributeValues[] = { &lineRotation };
  456. result = ATSUSetLayoutControls(vertTextLayout, 1, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
  457. }
  458. }
  459. //----------------------------------------------------------------------
  460. // Constructor
  461. // Author: pdaehne
  462. //----------------------------------------------------------------------
  463. TextMacVectorFace::TextMacVectorFace(ATSUStyle horiFontStyle)
  464. : TextVectorFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
  465. {
  466. // Create all ATSU objects
  467. createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
  468. // Try to get information about the face
  469. getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
  470. _horiAscent, _horiDescent, _vertAscent, _vertDescent);
  471. // Determine the scale factor
  472. _scale = 1.f / (_horiAscent - _horiDescent);
  473. // Determine ascent
  474. _horiAscent *= _scale;
  475. _vertAscent = -0.5f;
  476. // Determine descent
  477. _horiDescent *= _scale;
  478. _vertDescent = 0.5f;
  479. }
  480. //----------------------------------------------------------------------
  481. // Destructor
  482. // Author: pdaehne
  483. //----------------------------------------------------------------------
  484. TextMacVectorFace::~TextMacVectorFace()
  485. {
  486. // Dispose the layout objects
  487. ATSUDisposeTextLayout(_horiTextLayout);
  488. ATSUDisposeTextLayout(_vertTextLayout);
  489. // Dispose style objects
  490. ATSUDisposeStyle(_horiFontStyle);
  491. ATSUDisposeStyle(_vertFontStyle);
  492. }
  493. //----------------------------------------------------------------------
  494. // Converts a unicode string to utf16
  495. // RFC2781: UTF-16, an encoding of ISO 10646
  496. // Author: pdaehne
  497. //----------------------------------------------------------------------
  498. static void convertUnicodeToUTF16(const wstring &text, vector<UniChar> &utf16Text)
  499. {
  500. UniCharCount i, textTotalLength = text.length();
  501. utf16Text.clear();
  502. utf16Text.reserve(textTotalLength);
  503. for (i = 0; i < textTotalLength; ++i)
  504. {
  505. wchar_t unicode = text[i];
  506. if (unicode < 0x10000)
  507. utf16Text.push_back(unicode);
  508. else if (unicode < 0x110000)
  509. {
  510. unsigned long u = unicode - 0x10000;
  511. utf16Text.push_back(0xd800 | (u >> 10));
  512. utf16Text.push_back(0xdc00 | (u & 0x3ff));
  513. }
  514. }
  515. }
  516. //----------------------------------------------------------------------
  517. // Lays out one line of text
  518. // Author: pdaehne
  519. //----------------------------------------------------------------------
  520. void TextMacVectorFace::layout(const wstring &text, const TextLayoutParam &param,
  521. TextLayoutResult &layoutResult)
  522. {
  523. // Initialize return values
  524. layoutResult.clear();
  525. if (param.horizontal == true)
  526. layoutResult.textBounds[1] = _horiAscent - _horiDescent;
  527. else
  528. layoutResult.textBounds[0] = _vertDescent - _vertAscent;
  529. layoutResult.lineBounds.push_back(layoutResult.textBounds);
  530. // Convert the unicode string to utf16
  531. vector<UniChar> utf16Text;
  532. convertUnicodeToUTF16(text, utf16Text);
  533. if (utf16Text.empty() == true)
  534. return;
  535. // Check whether we have to use the horizontal or vertical ATSUI objects
  536. ATSUStyle fontStyle;
  537. ATSUTextLayout textLayout;
  538. if (param.horizontal == true)
  539. {
  540. fontStyle = _horiFontStyle;
  541. textLayout = _horiTextLayout;
  542. }
  543. else
  544. {
  545. fontStyle = _vertFontStyle;
  546. textLayout = _vertTextLayout;
  547. }
  548. // Set the length
  549. Real32 length = param.getLength(0);
  550. Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
  551. ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length / _scale);
  552. ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
  553. ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
  554. ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
  555. ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
  556. // Set the text
  557. OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
  558. if (result != noErr)
  559. return;
  560. // Set the style object
  561. result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
  562. if (result != noErr)
  563. return;
  564. // Get the layout records
  565. ATSLayoutRecord *layoutRecords;
  566. ItemCount numRecords;
  567. result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
  568. kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
  569. if (result != noErr)
  570. return;
  571. Fixed *deltaYs;
  572. ItemCount numDeltaYs;
  573. result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
  574. kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
  575. if (result != noErr)
  576. deltaYs = 0;
  577. // Calculate the positions of the glyphs
  578. layoutResult.indices.reserve(numRecords);
  579. layoutResult.positions.reserve(numRecords);
  580. ItemCount j;
  581. Vec2f currPos;
  582. for (j = 0; j < numRecords; ++j)
  583. {
  584. ATSGlyphRef glyphID = layoutRecords[j].glyphID;
  585. currPos[0] = FixedToFloat(layoutRecords[j].realPos) * _scale;
  586. currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) * _scale: 0.f;
  587. const TextVectorGlyph &glyph = getVectorGlyph(glyphID);
  588. if (param.horizontal == true)
  589. {
  590. currPos[0] += glyph.getHoriBearingX();
  591. currPos[1] += glyph.getHoriBearingY();
  592. }
  593. else
  594. {
  595. float h = currPos.x();
  596. currPos[0] = currPos.y() + glyph.getVertBearingX();
  597. currPos[1] = -h + glyph.getVertBearingY();
  598. }
  599. if (glyphID != kATSDeletedGlyphcode)
  600. {
  601. layoutResult.indices.push_back(glyphID);
  602. layoutResult.positions.push_back(currPos);
  603. }
  604. }
  605. // Cleanup
  606. if (deltaYs != 0)
  607. ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
  608. ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
  609. // Adjust the origin depending on the major and the minor alignment
  610. adjustLineOrigin(param, currPos, layoutResult);
  611. // Determine text bounds / line bounds
  612. if (param.horizontal == true)
  613. layoutResult.textBounds[0] = osgAbs(currPos.x());
  614. else
  615. layoutResult.textBounds[1] = osgAbs(currPos.y());
  616. assert(layoutResult.lineBounds.empty() == false);
  617. layoutResult.lineBounds.front() = layoutResult.textBounds;
  618. }
  619. //----------------------------------------------------------------------
  620. // Helper object used by the decompose callback functions
  621. // Author: pdaehne
  622. //----------------------------------------------------------------------
  623. typedef struct UserData
  624. {
  625. Real32 scale;
  626. Vec2f offset;
  627. TextVectorGlyph::Outline &outline;
  628. inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
  629. : scale(s), offset(off), outline(o)
  630. {}
  631. }
  632. UserData;
  633. //----------------------------------------------------------------------
  634. // callback function that starts a new contour
  635. // Author: pdaehne
  636. //----------------------------------------------------------------------
  637. static OSStatus quadraticNewPathCallback(void *callBackDataPtr)
  638. {
  639. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  640. // We start a new contour
  641. userData->outline.push_back(TextVectorGlyph::Contour());
  642. // Continue
  643. return noErr;
  644. }
  645. //----------------------------------------------------------------------
  646. // callback function that adds a line to the contour
  647. // Author: pdaehne
  648. //----------------------------------------------------------------------
  649. static OSStatus quadraticLineCallback(const Float32Point *pt1, const Float32Point *pt2, void *callBackDataPtr)
  650. {
  651. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  652. // When this is the first segment, we have to put the first point into the contour
  653. if (userData->outline.back().empty() == true)
  654. {
  655. Vec2f p(pt1->x, -pt1->y);
  656. p *= userData->scale;
  657. p -= userData->offset;
  658. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  659. }
  660. // We have a point on the line
  661. Vec2f p(pt2->x, -pt2->y);
  662. p *= userData->scale;
  663. p -= userData->offset;
  664. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  665. // Continue
  666. return noErr;
  667. }
  668. //----------------------------------------------------------------------
  669. // callback function that adds a quadratic Bezier spline to the contour
  670. // Author: pdaehne
  671. //----------------------------------------------------------------------
  672. static OSStatus quadraticCurveCallback(const Float32Point *pt1, const Float32Point *controlPt, const Float32Point *pt2, void *callBackDataPtr)
  673. {
  674. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  675. // When this is the first segment, we have to put the first point into the contour
  676. if (userData->outline.back().empty() == true)
  677. {
  678. Vec2f p(pt1->x, -pt1->y);
  679. p *= userData->scale;
  680. p -= userData->offset;
  681. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  682. }
  683. // We have a control point and a point on the line
  684. Vec2f p(controlPt->x, -controlPt->y);
  685. p *= userData->scale;
  686. p -= userData->offset;
  687. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
  688. p.setValues(pt2->x, -pt2->y);
  689. p *= userData->scale;
  690. p -= userData->offset;
  691. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  692. // Continue
  693. return noErr;
  694. }
  695. //----------------------------------------------------------------------
  696. // callback function that closes a contour
  697. // Author: pdaehne
  698. //----------------------------------------------------------------------
  699. OSStatus quadraticClosePathCallback(void *callBackDataPtr)
  700. {
  701. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  702. // Check if the contour is valid, i.e. if it has more than three points.
  703. // When not, we simply delete the contour.
  704. if (userData->outline.back().size() < 3)
  705. userData->outline.erase(userData->outline.end() - 1);
  706. // Continue
  707. return noErr;
  708. }
  709. //----------------------------------------------------------------------
  710. // callback function that starts a new contour
  711. // Author: pdaehne
  712. //----------------------------------------------------------------------
  713. static OSStatus cubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
  714. {
  715. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  716. // We start a new contour
  717. userData->outline.push_back(TextVectorGlyph::Contour());
  718. // We have a point on the line
  719. Vec2f p(pt->x, -pt->y);
  720. p *= userData->scale;
  721. p -= userData->offset;
  722. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  723. // Continue
  724. return noErr;
  725. }
  726. //----------------------------------------------------------------------
  727. // callback function that adds a line to the contour
  728. // Author: pdaehne
  729. //----------------------------------------------------------------------
  730. static OSStatus cubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
  731. {
  732. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  733. // We have a point on the line
  734. Vec2f p(pt->x, -pt->y);
  735. p *= userData->scale;
  736. p -= userData->offset;
  737. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  738. // Continue
  739. return noErr;
  740. }
  741. //----------------------------------------------------------------------
  742. // callback function that adds a cubic Bezier spline to the contour
  743. // Author: pdaehne
  744. //----------------------------------------------------------------------
  745. static OSStatus cubicCurveToCallback(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *callBackDataPtr)
  746. {
  747. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  748. // We have two control points and a point on the line
  749. Vec2f p(pt1->x, -pt1->y);
  750. p *= userData->scale;
  751. p -= userData->offset;
  752. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
  753. p.setValues(pt2->x, -pt2->y);
  754. p *= userData->scale;
  755. p -= userData->offset;
  756. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
  757. p.setValues(pt3->x, -pt3->y);
  758. p *= userData->scale;
  759. p -= userData->offset;
  760. userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
  761. // Continue
  762. return noErr;
  763. }
  764. //----------------------------------------------------------------------
  765. // callback function that closes a contour
  766. // Author: pdaehne
  767. //----------------------------------------------------------------------
  768. static OSStatus cubicClosePathCallback(void *callBackDataPtr)
  769. {
  770. UserData *userData = reinterpret_cast<UserData*>(callBackDataPtr);
  771. // Check if the contour is valid, i.e. if it has more than two points.
  772. // When not, we simply delete the contour.
  773. if (userData->outline.back().size() < 3)
  774. userData->outline.erase(userData->outline.end() - 1);
  775. // Continue
  776. return noErr;
  777. }
  778. //----------------------------------------------------------------------
  779. // Creates a new Glyph object
  780. // Author: pdaehne
  781. //----------------------------------------------------------------------
  782. auto_ptr<TextVectorGlyph> TextMacVectorFace::createGlyph(TextGlyph::Index glyphIndex)
  783. {
  784. // We cannot create glyphs for invalid glyph indices
  785. if (glyphIndex == TextGlyph::INVALID_INDEX)
  786. return auto_ptr<TextVectorGlyph>();
  787. // Create and return the new glyph object
  788. return auto_ptr<TextVectorGlyph>(new TextMacVectorGlyph(glyphIndex, _scale, _horiFontStyle, _vertFontStyle));
  789. }
  790. //----------------------------------------------------------------------
  791. // Constructor
  792. // Author: pdaehne
  793. //----------------------------------------------------------------------
  794. TextMacVectorGlyph::TextMacVectorGlyph(Index glyphIndex, Real32 scale, ATSUStyle horiFontStyle, ATSUStyle vertFontStyle)
  795. : TextVectorGlyph()
  796. {
  797. _glyphIndex = glyphIndex;
  798. // Determine horizontal glyph metrics
  799. GlyphID glyphID = _glyphIndex;
  800. ATSGlyphScreenMetrics glyphScreenMetrics;
  801. OSStatus result = ATSUGlyphGetScreenMetrics(horiFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
  802. if (result == noErr)
  803. {
  804. _width = glyphScreenMetrics.width * scale;
  805. _height = glyphScreenMetrics.height * scale;
  806. _horiAdvance = glyphScreenMetrics.deviceAdvance.x * scale;
  807. _horiBearingX = glyphScreenMetrics.topLeft.x * scale;
  808. _horiBearingY = glyphScreenMetrics.topLeft.y * scale;
  809. }
  810. // Determine vertical glyph metrics
  811. result = ATSUGlyphGetScreenMetrics(vertFontStyle, 1, &glyphID, 0, false, false, &glyphScreenMetrics);
  812. if (result == noErr)
  813. {
  814. _width = glyphScreenMetrics.width * scale;
  815. _height = glyphScreenMetrics.height * scale;
  816. _vertAdvance = glyphScreenMetrics.deviceAdvance.y * scale;
  817. _vertBearingX = glyphScreenMetrics.topLeft.x * scale;
  818. _vertBearingY = glyphScreenMetrics.topLeft.y * scale;
  819. }
  820. // Get the outlines
  821. ATSCurveType curveType;
  822. result = ATSUGetNativeCurveType(horiFontStyle, &curveType);
  823. if (result != noErr)
  824. return;
  825. if (curveType == kATSQuadCurveType)
  826. {
  827. // This is quite ugly, we should do this only once for all glyphs.
  828. // But on MacOS X, this should be a NOP, anyway.
  829. ATSQuadraticNewPathUPP newPathProc = NewATSQuadraticNewPathUPP(&quadraticNewPathCallback);
  830. ATSQuadraticLineUPP lineProc = NewATSQuadraticLineUPP(&quadraticLineCallback);
  831. ATSQuadraticCurveUPP curveProc = NewATSQuadraticCurveUPP(&quadraticCurveCallback);
  832. ATSQuadraticClosePathUPP closePathProc = NewATSQuadraticClosePathUPP(&quadraticClosePathCallback);
  833. UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
  834. OSStatus callbackResult;
  835. result = ATSUGlyphGetQuadraticPaths(horiFontStyle, glyphID, newPathProc, lineProc, curveProc, closePathProc, &userData, &callbackResult);
  836. DisposeATSQuadraticClosePathUPP(closePathProc);
  837. DisposeATSQuadraticCurveUPP(curveProc);
  838. DisposeATSQuadraticLineUPP(lineProc);
  839. DisposeATSQuadraticNewPathUPP(newPathProc);
  840. }
  841. else if (curveType == kATSCubicCurveType)
  842. {
  843. // This is quite ugly, we should do this only once for all glyphs.
  844. // But on MacOS X, this should be a NOP, anyway.
  845. ATSCubicMoveToUPP moveToProc = NewATSCubicMoveToUPP(&cubicMoveToCallback);
  846. ATSCubicLineToUPP lineToProc = NewATSCubicLineToUPP(&cubicLineToCallback);
  847. ATSCubicCurveToUPP curveToProc = NewATSCubicCurveToUPP(&cubicCurveToCallback);
  848. ATSCubicClosePathUPP closePathProc = NewATSCubicClosePathUPP(&cubicClosePathCallback);
  849. UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
  850. OSStatus callbackResult;
  851. ATSUGlyphGetCubicPaths(horiFontStyle, glyphID, moveToProc, lineToProc, curveToProc, closePathProc, &userData, &callbackResult);
  852. DisposeATSCubicClosePathUPP(closePathProc);
  853. DisposeATSCubicCurveToUPP(curveToProc);
  854. DisposeATSCubicLineToUPP(lineToProc);
  855. DisposeATSCubicMoveToUPP(moveToProc);
  856. }
  857. }
  858. //----------------------------------------------------------------------
  859. // Destructor
  860. // Author: pdaehne
  861. //----------------------------------------------------------------------
  862. TextMacVectorGlyph::~TextMacVectorGlyph() {}
  863. //----------------------------------------------------------------------
  864. // Constructor
  865. // Author: pdaehne
  866. //----------------------------------------------------------------------
  867. TextMacPixmapFace::TextMacPixmapFace(ATSUStyle horiFontStyle)
  868. : TextPixmapFace(), _horiFontStyle(horiFontStyle), _vertFontStyle(0), _horiTextLayout(0), _vertTextLayout(0)
  869. {
  870. // Create all ATSU objects
  871. createATSUObjects(_horiFontStyle, _vertFontStyle, _horiTextLayout, _vertTextLayout);
  872. // Try to get information about the face
  873. getFaceInfo(_horiFontStyle, _vertFontStyle, _family, _style,
  874. _horiAscent, _horiDescent, _vertAscent, _vertDescent);
  875. // Determine the size
  876. Fixed size;
  877. OSStatus result = ATSUGetAttribute(_horiFontStyle, kATSUSizeTag, sizeof(size), &size, 0);
  878. _size = ((result == noErr) || (result == kATSUNotSetErr)) ? FixedToInt(size) : 0;
  879. }
  880. //----------------------------------------------------------------------
  881. // Destructor
  882. // Author: pdaehne
  883. //----------------------------------------------------------------------
  884. TextMacPixmapFace::~TextMacPixmapFace()
  885. {
  886. // Dispose the layout objects
  887. ATSUDisposeTextLayout(_horiTextLayout);
  888. ATSUDisposeTextLayout(_vertTextLayout);
  889. // Dispose style objects
  890. ATSUDisposeStyle(_horiFontStyle);
  891. ATSUDisposeStyle(_vertFontStyle);
  892. }
  893. //----------------------------------------------------------------------
  894. // Lays out one line of text
  895. // Author: pdaehne
  896. //----------------------------------------------------------------------
  897. void TextMacPixmapFace::layout(const wstring &text, const TextLayoutParam &param,
  898. TextLayoutResult &layoutResult)
  899. {
  900. // Initialize return values
  901. layoutResult.clear();
  902. if (param.horizontal == true)
  903. layoutResult.textBounds[1] = _horiAscent - _horiDescent;
  904. else
  905. layoutResult.textBounds[0] = _vertDescent - _vertAscent;
  906. layoutResult.lineBounds.push_back(layoutResult.textBounds);
  907. // Convert the unicode string to utf16
  908. vector<UniChar> utf16Text;
  909. convertUnicodeToUTF16(text, utf16Text);
  910. if (utf16Text.empty() == true)
  911. return;
  912. // Check whether we have to use the horizontal or vertical ATSUI objects
  913. ATSUStyle fontStyle;
  914. ATSUTextLayout textLayout;
  915. if (param.horizontal == true)
  916. {
  917. fontStyle = _horiFontStyle;
  918. textLayout = _horiTextLayout;
  919. }
  920. else
  921. {
  922. fontStyle = _vertFontStyle;
  923. textLayout = _vertTextLayout;
  924. }
  925. // Set the length
  926. Real32 length = param.getLength(0);
  927. Fract justFactor = length <= 0.f ? kATSUNoJustification : kATSUFullJustification;
  928. ATSUTextMeasurement width = FloatToFixed(length <= 0.f ? 0.f : length);
  929. ATSUAttributeTag layoutAttributeTags[] = { kATSULineJustificationFactorTag, kATSULineWidthTag };
  930. ByteCount layoutAttributeSizes[] = { sizeof(justFactor), sizeof(width) };
  931. ATSUAttributeValuePtr layoutAttributeValues[] = { &justFactor, &width };
  932. ATSUSetLayoutControls(textLayout, 2, layoutAttributeTags, layoutAttributeSizes, layoutAttributeValues);
  933. // Set the text
  934. OSStatus result = ATSUSetTextPointerLocation(textLayout, &(utf16Text[0]), kATSUFromTextBeginning, kATSUToTextEnd, utf16Text.size());
  935. if (result != noErr)
  936. return;
  937. // Set the style object
  938. result = ATSUSetRunStyle(textLayout, fontStyle, kATSUFromTextBeginning, kATSUToTextEnd);
  939. if (result != noErr)
  940. return;
  941. // Get the layout records
  942. ATSLayoutRecord *layoutRecords;
  943. ItemCount numRecords;
  944. result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
  945. kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords, &numRecords);
  946. if (result != noErr)
  947. return;
  948. Fixed *deltaYs;
  949. ItemCount numDeltaYs;
  950. result = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, kATSUFromTextBeginning,
  951. kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs, &numDeltaYs);
  952. if (result != noErr)
  953. deltaYs = 0;
  954. // Calculate the positions of the glyphs
  955. layoutResult.indices.reserve(numRecords);
  956. layoutResult.positions.reserve(numRecords);
  957. ItemCount j;
  958. Vec2f currPos;
  959. for (j = 0; j < numRecords; ++j)
  960. {
  961. ATSGlyphRef glyphID = layoutRecords[j].glyphID;
  962. currPos[0] = FixedToFloat(layoutRecords[j].realPos);
  963. currPos[1] = (deltaYs != 0) && (j < numDeltaYs) ? -FixedToFloat(deltaYs[j]) : 0.f;
  964. const TextPixmapGlyph &glyph = getPixmapGlyph(layoutRecords[j], param.horizontal);
  965. if (param.horizontal == true)
  966. {
  967. currPos[0] += glyph.getHoriBearingX();
  968. currPos[1] += glyph.getHoriBearingY();
  969. }
  970. else
  971. {
  972. float h = currPos.x();
  973. currPos[0] = currPos.y() + glyph.getVertBearingX();
  974. currPos[1] = -h + glyph.getVertBearingY();
  975. }
  976. if (glyphID != kATSDeletedGlyphcode)
  977. {
  978. layoutResult.indices.push_back(glyphID);
  979. layoutResult.positions.push_back(currPos);
  980. }
  981. }
  982. // Cleanup
  983. if (deltaYs != 0)
  984. ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataBaselineDeltaFixedArray, (void**)&deltaYs);
  985. ATSUDirectReleaseLayoutDataArrayPtr(0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&layoutRecords);
  986. // Adjust the origin depending on the major and the minor alignment
  987. adjustLineOrigin(param, currPos, layoutResult);
  988. // Determine text bounds / line bounds
  989. if (param.horizontal == true)
  990. layoutResult.textBounds[0] = osgAbs(currPos.x());
  991. else
  992. layoutResult.textBounds[1] = osgAbs(currPos.y());
  993. assert(layoutResult.lineBounds.empty() == false);
  994. layoutResult.lineBounds.front() = layoutResult.textBounds;
  995. }
  996. //----------------------------------------------------------------------
  997. // Creates a new Glyph object
  998. // Author: pdaehne
  999. //----------------------------------------------------------------------
  1000. auto_ptr<TextPixmapGlyph> TextMacPixmapFace::createGlyph(TextGlyph::Index glyphIndex)
  1001. {
  1002. return auto_ptr<TextPixmapGlyph>();
  1003. }
  1004. //----------------------------------------------------------------------
  1005. // Renders a glyph into a memory buffer
  1006. // Author: pdaehne
  1007. //----------------------------------------------------------------------
  1008. static void drawGlyph(ATSUTextLayout textLayout, const ATSLayoutRecord &layoutRecord,
  1009. ATSUTextMeasurement xPos, ATSUTextMeasurement yPos,
  1010. UInt32 width, UInt32 height, UInt8 *dst, UInt32 pitch)
  1011. {
  1012. // No need to draw invisible glyphs
  1013. if ((width == 0) || (height == 0))
  1014. return;
  1015. // Create offscreen GWorld
  1016. GWorldPtr offscreenGWorld;
  1017. Rect boundsRect;
  1018. SetRect(&boundsRect, 0, 0, width, height);
  1019. QDErr qdResult = NewGWorld(&offscreenGWorld, 32, &boundsRect, 0, 0, 0);
  1020. if (qdResult != noErr)
  1021. return;
  1022. // Get the pixel buffer of the offscreen GWorld
  1023. if (LockPixels(GetGWorldPixMap(offscreenGWorld)) == FALSE)
  1024. {
  1025. DisposeGWorld(offscreenGWorld);
  1026. return;
  1027. }
  1028. Ptr src = GetPixBaseAddr(GetGWorldPixMap(offscreenGWorld));
  1029. if (src == 0)
  1030. {
  1031. UnlockPixels(GetGWorldPixMap(offscreenGWorld));
  1032. DisposeGWorld(offscreenGWorld);
  1033. return;
  1034. }
  1035. // Initialize and activate the offscreen GWorld
  1036. CGrafPtr port;
  1037. GDHandle gdh;
  1038. GetGWorld(&port, &gdh);
  1039. SetGWorld(offscreenGWorld, 0);
  1040. RGBColor gBlackColour = { 0x0000, 0x0000, 0x0000 };
  1041. RGBBackColor(&gBlackColour);
  1042. EraseRect(&boundsRect);
  1043. RGBColor gWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
  1044. RGBForeColor(&gWhiteColour);
  1045. // Draw the text
  1046. UniCharArrayOffset charOffset = layoutRecord.originalOffset >> 1;
  1047. UniCharCount charCount = (layoutRecord.flags & kATSGlyphInfoByteSizeMask) >> 1;
  1048. OSStatus result = ATSUDrawText(textLayout, charOffset, charCount, xPos, yPos);
  1049. if (result == noErr)
  1050. {
  1051. long bpl = GetPixRowBytes(GetGWorldPixMap(offscreenGWorld));
  1052. src += bpl * (height - 1);
  1053. Ptr src2;
  1054. UInt32 x, y;
  1055. for (y = 0; y < height; ++y)
  1056. {
  1057. src2 = src + 1;
  1058. for (x = 0; x < width; ++x)
  1059. {
  1060. *dst++ = *src2;
  1061. src2+= 4;
  1062. }
  1063. src -= bpl;
  1064. dst += pitch;
  1065. }
  1066. }
  1067. // Deactivate and destroy the offscreen GWorld
  1068. SetGWorld(port, gdh);
  1069. UnlockPixels(GetGWorldPixMap(offscreenGWorld));
  1070. DisposeGWorld(offscreenGWorld);
  1071. }
  1072. //----------------------------------------------------------------------
  1073. // Returns information about a glyph.
  1074. // Author: pdaehne
  1075. //----------------------------------------------------------------------
  1076. const TextPixmapGlyph &TextMacPixmapFace::getPixmapGlyph(const ATSLayoutRecord &layoutRecord, bool horizontal)
  1077. {
  1078. ATSGlyphRef glyphID = layoutRecord.glyphID;
  1079. if (glyphID == kATSDeletedGlyphcode)
  1080. return _emptyGlyph;
  1081. // Try to find the glyph in the map of glyphs
  1082. GlyphMap::const_iterator it = _glyphMap.find(glyphID);
  1083. if (it != _glyphMap.end())
  1084. {
  1085. assert(it->second != 0);
  1086. return *(it->second);
  1087. }
  1088. // We did not find the glyph, so we have to create it
  1089. ATSUTextMeasurement xPos = 0, yPos = 0;
  1090. // Determine horizontal glyph metrics
  1091. ATSGlyphScreenMetrics glyphScreenMetrics;
  1092. OSStatus result = ATSUGlyphGetScreenMetrics(_horiFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
  1093. if (result != noErr)
  1094. return _emptyGlyph;
  1095. Real32 horiAdvance = glyphScreenMetrics.deviceAdvance.x;
  1096. UInt32 width = glyphScreenMetrics.width;
  1097. UInt32 height = glyphScreenMetrics.height;
  1098. Int32 horiBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
  1099. Int32 horiBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
  1100. if (horizontal == true)
  1101. {
  1102. xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x) - (layoutRecord.realPos & 0xffff0000);
  1103. yPos = FloatToFixed(glyphScreenMetrics.topLeft.y);
  1104. }
  1105. // Determine vertical glyph metrics
  1106. result = ATSUGlyphGetScreenMetrics(_vertFontStyle, 1, &glyphID, 0, true, true, &glyphScreenMetrics);
  1107. if (result != noErr)
  1108. return _emptyGlyph;
  1109. Real32 vertAdvance = glyphScreenMetrics.deviceAdvance.y;
  1110. Int32 vertBearingX = static_cast<Int32>(glyphScreenMetrics.topLeft.x);
  1111. Int32 vertBearingY = static_cast<Int32>(glyphScreenMetrics.topLeft.y);
  1112. if (horizontal == false)
  1113. {
  1114. xPos = FloatToFixed(-glyphScreenMetrics.topLeft.x);
  1115. yPos = FloatToFixed(glyphScreenMetrics.topLeft.y) - ((layoutRecord.realPos + fixed1) & 0xffff0000);
  1116. }
  1117. UInt8 *pixmap = 0;
  1118. UInt32 size = width * height;
  1119. if (size != 0)
  1120. {
  1121. // Create pixmap
  1122. ATSUTextLayout textLayout = horizontal == true ? _horiTextLayout : _vertTextLayout;
  1123. pixmap = new UInt8[size];
  1124. drawGlyph(textLayout, layoutRecord, xPos, yPos, width, height, pixmap, 0);
  1125. }
  1126. auto_ptr<TextPixmapGlyph> glyph(new TextMacPixmapGlyph(glyphID, width, height, horiAdvance, horiBearingX, horiBearingY, vertAdvance, vertBearingX, vertBearingY, pixmap));
  1127. // Put the glyph into the glyph cache
  1128. _glyphMap.insert(GlyphMap::value_type(glyphID, glyph.get()));
  1129. // Return the glyph
  1130. return *(glyph.release());
  1131. }
  1132. //----------------------------------------------------------------------
  1133. // Constructor
  1134. // Author: pdaehne
  1135. //----------------------------------------------------------------------
  1136. TextMacPixmapGlyph::TextMacPixmapGlyph(Index glyphIndex, UInt32 width, UInt32 height,
  1137. Real32 horiAdvance, Int32 horiBearingX, Int32 horiBearingY,
  1138. Real32

Large files files are truncated, but you can click here to view the full file