PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/vcl/aqua/source/gdi/atsui/salgdi.cxx

https://bitbucket.org/markjenkins/libreoffice_ubuntu-debian-fixes
C++ | 1159 lines | 844 code | 178 blank | 137 comment | 168 complexity | 8d1d2fcd5f8da565b104452683f69e74 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause-No-Nuclear-License-2014
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3. * This file is part of the LibreOffice project.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. * This file incorporates work covered by the following license notice:
  10. *
  11. * Licensed to the Apache Software Foundation (ASF) under one or more
  12. * contributor license agreements. See the NOTICE file distributed
  13. * with this work for additional information regarding copyright
  14. * ownership. The ASF licenses this file to you under the Apache
  15. * License, Version 2.0 (the "License"); you may not use this file
  16. * except in compliance with the License. You may obtain a copy of
  17. * the License at http://www.apache.org/licenses/LICENSE-2.0 .
  18. */
  19. #include "osl/file.hxx"
  20. #include "osl/process.h"
  21. #include "osl/mutex.hxx"
  22. #include "rtl/bootstrap.h"
  23. #include "rtl/strbuf.hxx"
  24. #include "basegfx/range/b2drectangle.hxx"
  25. #include "basegfx/polygon/b2dpolygon.hxx"
  26. #include "basegfx/polygon/b2dpolygontools.hxx"
  27. #include "basegfx/matrix/b2dhommatrix.hxx"
  28. #include "basegfx/matrix/b2dhommatrixtools.hxx"
  29. #include "vcl/sysdata.hxx"
  30. #include "vcl/svapp.hxx"
  31. #include "aqua/salconst.h"
  32. #include "aqua/atsui/salgdi.h"
  33. #include "aqua/salbmp.h"
  34. #include "aqua/salframe.h"
  35. #include "aqua/salcolorutils.hxx"
  36. #include "aqua/atsui/salatsuifontutils.hxx"
  37. #include "fontsubset.hxx"
  38. #include "impfont.hxx"
  39. #include "sallayout.hxx"
  40. #include "sft.hxx"
  41. using namespace vcl;
  42. //typedef unsigned char Boolean; // copied from MacTypes.h, should be properly included
  43. typedef std::vector<unsigned char> ByteVector;
  44. // ATSUI is deprecated in 10.6 (or already 10.5?)
  45. #if defined LIBO_WERROR && defined __GNUC__
  46. #define GCC_VERSION (__GNUC__ * 10000 \
  47. + __GNUC_MINOR__ * 100 \
  48. + __GNUC_PATCHLEVEL__)
  49. #if GCC_VERSION >= 40201
  50. #pragma GCC diagnostic warning "-Wdeprecated-declarations"
  51. #endif
  52. #endif
  53. // =======================================================================
  54. ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
  55. : PhysicalFontFace( rDFA, 0 )
  56. , mnFontId( nFontId )
  57. , mpCharMap( NULL )
  58. , mbOs2Read( false )
  59. , mbHasOs2Table( false )
  60. , mbCmapEncodingRead( false )
  61. , mbHasCJKSupport( false )
  62. , mbFontCapabilitiesRead( false )
  63. {}
  64. // -----------------------------------------------------------------------
  65. ImplMacFontData::~ImplMacFontData()
  66. {
  67. if( mpCharMap )
  68. mpCharMap->DeReference();
  69. }
  70. // -----------------------------------------------------------------------
  71. sal_IntPtr ImplMacFontData::GetFontId() const
  72. {
  73. return (sal_IntPtr)mnFontId;
  74. }
  75. // -----------------------------------------------------------------------
  76. PhysicalFontFace* ImplMacFontData::Clone() const
  77. {
  78. ImplMacFontData* pClone = new ImplMacFontData(*this);
  79. if( mpCharMap )
  80. mpCharMap->AddReference();
  81. return pClone;
  82. }
  83. // -----------------------------------------------------------------------
  84. ImplFontEntry* ImplMacFontData::CreateFontInstance(FontSelectPattern& rFSD) const
  85. {
  86. return new ImplFontEntry(rFSD);
  87. }
  88. // -----------------------------------------------------------------------
  89. inline FourCharCode GetTag(const char aTagName[5])
  90. {
  91. return (aTagName[0]<<24)+(aTagName[1]<<16)+(aTagName[2]<<8)+(aTagName[3]);
  92. }
  93. static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
  94. static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
  95. #if MACOSX_SDK_VERSION >= 1070
  96. extern "C" {
  97. extern ATSFontRef FMGetATSFontRefFromFont(FMFont iFont);
  98. }
  99. #endif
  100. const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
  101. {
  102. // return the cached charmap
  103. if( mpCharMap )
  104. return mpCharMap;
  105. // set the default charmap
  106. mpCharMap = ImplFontCharMap::GetDefaultMap();
  107. mpCharMap->AddReference();
  108. // get the CMAP byte size
  109. ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
  110. ByteCount nBufSize = 0;
  111. OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
  112. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable1 failed!\n");
  113. if( eStatus != noErr )
  114. return mpCharMap;
  115. // allocate a buffer for the CMAP raw data
  116. ByteVector aBuffer( nBufSize );
  117. // get the CMAP raw data
  118. ByteCount nRawLength = 0;
  119. eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
  120. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable2 failed!\n");
  121. if( eStatus != noErr )
  122. return mpCharMap;
  123. DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
  124. // parse the CMAP
  125. CmapResult aCmapResult;
  126. if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
  127. {
  128. // create the matching charmap
  129. mpCharMap->DeReference();
  130. mpCharMap = new ImplFontCharMap( aCmapResult );
  131. mpCharMap->AddReference();
  132. }
  133. return mpCharMap;
  134. }
  135. bool ImplMacFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
  136. {
  137. // read this only once per font
  138. if( mbFontCapabilitiesRead )
  139. {
  140. rFontCapabilities = maFontCapabilities;
  141. return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
  142. }
  143. mbFontCapabilitiesRead = true;
  144. // prepare to get the GSUB table raw data
  145. ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
  146. ByteCount nBufSize = 0;
  147. OSStatus eStatus;
  148. eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, 0, NULL, &nBufSize );
  149. if( eStatus == noErr )
  150. {
  151. // allocate a buffer for the GSUB raw data
  152. ByteVector aBuffer( nBufSize );
  153. // get the GSUB raw data
  154. ByteCount nRawLength = 0;
  155. eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
  156. if( eStatus == noErr )
  157. {
  158. const unsigned char* pGSUBTable = &aBuffer[0];
  159. vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
  160. }
  161. }
  162. eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
  163. if( eStatus == noErr )
  164. {
  165. // allocate a buffer for the GSUB raw data
  166. ByteVector aBuffer( nBufSize );
  167. // get the OS/2 raw data
  168. ByteCount nRawLength = 0;
  169. eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
  170. if( eStatus == noErr )
  171. {
  172. const unsigned char* pOS2Table = &aBuffer[0];
  173. vcl::getTTCoverage(
  174. maFontCapabilities.maUnicodeRange,
  175. maFontCapabilities.maCodePageRange,
  176. pOS2Table, nRawLength);
  177. }
  178. }
  179. rFontCapabilities = maFontCapabilities;
  180. return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
  181. }
  182. // -----------------------------------------------------------------------
  183. void ImplMacFontData::ReadOs2Table( void ) const
  184. {
  185. // read this only once per font
  186. if( mbOs2Read )
  187. return;
  188. mbOs2Read = true;
  189. // prepare to get the OS/2 table raw data
  190. ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
  191. ByteCount nBufSize = 0;
  192. OSStatus eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
  193. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable1 failed!\n");
  194. if( eStatus != noErr )
  195. return;
  196. // allocate a buffer for the OS/2 raw data
  197. ByteVector aBuffer( nBufSize );
  198. // get the OS/2 raw data
  199. ByteCount nRawLength = 0;
  200. eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
  201. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable2 failed!\n");
  202. if( eStatus != noErr )
  203. return;
  204. DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
  205. mbHasOs2Table = true;
  206. // parse the OS/2 raw data
  207. // TODO: also analyze panose info, etc.
  208. // check if the fonts needs the "CJK extra leading" heuristic
  209. const unsigned char* pOS2map = &aBuffer[0];
  210. const sal_uInt32 nVersion = GetUShort( pOS2map );
  211. if( nVersion >= 0x0001 )
  212. {
  213. sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
  214. if( ulUnicodeRange2 & 0x2DF00000 )
  215. mbHasCJKSupport = true;
  216. }
  217. }
  218. void ImplMacFontData::ReadMacCmapEncoding( void ) const
  219. {
  220. // read this only once per font
  221. if( mbCmapEncodingRead )
  222. return;
  223. mbCmapEncodingRead = true;
  224. ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
  225. ByteCount nBufSize = 0;
  226. OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
  227. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable1 failed!\n");
  228. if( eStatus != noErr )
  229. return;
  230. ByteVector aBuffer( nBufSize );
  231. ByteCount nRawLength = 0;
  232. eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
  233. DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable2 failed!\n");
  234. if( eStatus != noErr )
  235. return;
  236. DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
  237. const unsigned char* pCmap = &aBuffer[0];
  238. if (nRawLength < 24 )
  239. return;
  240. if( GetUShort( pCmap ) != 0x0000 )
  241. return;
  242. // check if the fonts needs the "CJK extra leading" heuristic
  243. int nSubTables = GetUShort( pCmap + 2 );
  244. for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
  245. {
  246. int nPlatform = GetUShort( p );
  247. if( nPlatform == kFontMacintoshPlatform ) {
  248. int nEncoding = GetUShort (p + 2 );
  249. if( nEncoding == kFontJapaneseScript ||
  250. nEncoding == kFontTraditionalChineseScript ||
  251. nEncoding == kFontKoreanScript ||
  252. nEncoding == kFontSimpleChineseScript )
  253. {
  254. mbHasCJKSupport = true;
  255. break;
  256. }
  257. }
  258. }
  259. }
  260. // -----------------------------------------------------------------------
  261. bool ImplMacFontData::HasCJKSupport( void ) const
  262. {
  263. ReadOs2Table();
  264. if( !mbHasOs2Table )
  265. ReadMacCmapEncoding();
  266. return mbHasCJKSupport;
  267. }
  268. // =======================================================================
  269. AquaSalGraphics::AquaSalGraphics()
  270. : mpFrame( NULL )
  271. , mxLayer( NULL )
  272. , mrContext( NULL )
  273. , mpXorEmulation( NULL )
  274. , mnXorMode( 0 )
  275. , mnWidth( 0 )
  276. , mnHeight( 0 )
  277. , mnBitmapDepth( 0 )
  278. , mnRealDPIX( 0 )
  279. , mnRealDPIY( 0 )
  280. , mfFakeDPIScale( 1.0 )
  281. , mxClipPath( NULL )
  282. , maLineColor( COL_WHITE )
  283. , maFillColor( COL_BLACK )
  284. , mpMacFontData( NULL )
  285. , mnATSUIRotation( 0 )
  286. , mfFontScale( 1.0 )
  287. , mfFontStretch( 1.0 )
  288. , mbNonAntialiasedText( false )
  289. , mbPrinter( false )
  290. , mbVirDev( false )
  291. , mbWindow( false )
  292. {
  293. // create the style object for font attributes
  294. ATSUCreateStyle( &maATSUStyle );
  295. }
  296. // -----------------------------------------------------------------------
  297. AquaSalGraphics::~AquaSalGraphics()
  298. {
  299. CGPathRelease( mxClipPath );
  300. ATSUDisposeStyle( maATSUStyle );
  301. if( mpXorEmulation )
  302. delete mpXorEmulation;
  303. if( mxLayer )
  304. CGLayerRelease( mxLayer );
  305. else if( mrContext && mbWindow )
  306. {
  307. // destroy backbuffer bitmap context that we created ourself
  308. CGContextRelease( mrContext );
  309. mrContext = NULL;
  310. // memory is freed automatically by maOwnContextMemory
  311. }
  312. }
  313. // =======================================================================
  314. void AquaSalGraphics::SetTextColor( SalColor nSalColor )
  315. {
  316. RGBColor color;
  317. color.red = (unsigned short) ( SALCOLOR_RED(nSalColor) * 65535.0 / 255.0 );
  318. color.green = (unsigned short) ( SALCOLOR_GREEN(nSalColor) * 65535.0 / 255.0 );
  319. color.blue = (unsigned short) ( SALCOLOR_BLUE(nSalColor) * 65535.0 / 255.0 );
  320. ATSUAttributeTag aTag = kATSUColorTag;
  321. ByteCount aValueSize = sizeof( color );
  322. ATSUAttributeValuePtr aValue = &color;
  323. OSStatus err = ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
  324. DBG_ASSERT( (err==noErr), "AquaSalGraphics::SetTextColor() : Could not set font attributes!\n");
  325. if( err != noErr )
  326. return;
  327. }
  328. // -----------------------------------------------------------------------
  329. void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
  330. {
  331. (void)nFallbackLevel; // glyph-fallback on ATSU is done differently -> no fallback level
  332. // get the ATSU font metrics (in point units)
  333. // of the font that has eventually been size-limited
  334. ATSUFontID fontId;
  335. OSStatus err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
  336. DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
  337. ATSFontMetrics aMetrics;
  338. ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
  339. err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
  340. DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
  341. if( err != noErr )
  342. return;
  343. // all ATS fonts are scalable fonts
  344. pMetric->mbScalableFont = true;
  345. // TODO: check if any kerning is possible
  346. pMetric->mbKernableFont = true;
  347. // convert into VCL font metrics (in unscaled pixel units)
  348. Fixed ptSize;
  349. err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
  350. DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
  351. const double fPointSize = Fix2X( ptSize );
  352. // convert quartz units to pixel units
  353. // please see the comment in AquaSalGraphics::SetFont() for details
  354. const double fPixelSize = (mfFontScale * mfFakeDPIScale * fPointSize);
  355. pMetric->mnAscent = static_cast<long>(+aMetrics.ascent * fPixelSize + 0.5);
  356. pMetric->mnDescent = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
  357. const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
  358. pMetric->mnExtLeading = nExtDescent - pMetric->mnDescent;
  359. pMetric->mnIntLeading = 0;
  360. // ATSFontMetrics.avgAdvanceWidth is obsolete, so it is usually set to zero
  361. // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
  362. // setting this width to the pixel height of the fontsize is good enough
  363. // it also makes the calculation of the stretch factor simple
  364. pMetric->mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
  365. }
  366. // -----------------------------------------------------------------------
  367. sal_uLong AquaSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* )
  368. {
  369. return 0;
  370. }
  371. // -----------------------------------------------------------------------
  372. static bool AddTempFontDir( const char* pDir )
  373. {
  374. FSRef aPathFSRef;
  375. Boolean bIsDirectory = true;
  376. OSStatus eStatus = FSPathMakeRef( reinterpret_cast<const UInt8*>(pDir), &aPathFSRef, &bIsDirectory );
  377. DBG_ASSERTWARNING( (eStatus==noErr) && bIsDirectory, "vcl AddTempFontDir() with invalid directory name!" );
  378. if( eStatus != noErr )
  379. return false;
  380. // TODO: deactivate ATSFontContainerRef when closing app
  381. ATSFontContainerRef aATSFontContainer;
  382. const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
  383. #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
  384. eStatus = ::ATSFontActivateFromFileReference( &aPathFSRef,
  385. eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
  386. &aATSFontContainer );
  387. #else
  388. FSSpec aPathFSSpec;
  389. eStatus = ::FSGetCatalogInfo( &aPathFSRef, kFSCatInfoNone,
  390. NULL, NULL, &aPathFSSpec, NULL );
  391. if( eStatus != noErr )
  392. return false;
  393. eStatus = ::ATSFontActivateFromFileSpecification( &aPathFSSpec,
  394. eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
  395. &aATSFontContainer );
  396. #endif
  397. if( eStatus != noErr )
  398. return false;
  399. return true;
  400. }
  401. static bool AddLocalTempFontDirs( void )
  402. {
  403. static bool bFirst = true;
  404. if( !bFirst )
  405. return false;
  406. bFirst = false;
  407. // add private font files
  408. rtl::OUString aBrandStr( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR" ) );
  409. rtl_bootstrap_expandMacros( &aBrandStr.pData );
  410. rtl::OUString aBrandSysPath;
  411. OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None );
  412. rtl::OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 );
  413. aBrandFontDir.append( rtl::OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) );
  414. aBrandFontDir.append( "/share/fonts/truetype/" );
  415. return AddTempFontDir( aBrandFontDir.getStr() );
  416. }
  417. void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
  418. {
  419. DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
  420. AddLocalTempFontDirs();
  421. // The idea is to cache the list of system fonts once it has been generated.
  422. // SalData seems to be a good place for this caching. However we have to
  423. // carefully make the access to the font list thread-safe. If we register
  424. // a font-change event handler to update the font list in case fonts have
  425. // changed on the system we have to lock access to the list. The right
  426. // way to do that is the solar mutex since GetDevFontList is protected
  427. // through it as should be all event handlers
  428. SalData* pSalData = GetSalData();
  429. if (pSalData->mpFontList == NULL)
  430. pSalData->mpFontList = new SystemFontList();
  431. // Copy all PhysicalFontFace objects contained in the SystemFontList
  432. pSalData->mpFontList->AnnounceFonts( *pFontList );
  433. }
  434. void AquaSalGraphics::ClearDevFontCache()
  435. {
  436. SalData* pSalData = GetSalData();
  437. delete pSalData->mpFontList;
  438. pSalData->mpFontList = NULL;
  439. }
  440. // -----------------------------------------------------------------------
  441. bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
  442. const rtl::OUString& rFontFileURL, const rtl::OUString& /*rFontName*/ )
  443. {
  444. ::rtl::OUString aUSytemPath;
  445. OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
  446. FSRef aNewRef;
  447. Boolean bIsDirectory = true;
  448. ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
  449. OSStatus eStatus = FSPathMakeRef( (UInt8*)aCFileName.getStr(), &aNewRef, &bIsDirectory );
  450. DBG_ASSERT( (eStatus==noErr) && !bIsDirectory, "vcl AddTempDevFont() with invalid fontfile name!" );
  451. if( eStatus != noErr )
  452. return false;
  453. ATSFontContainerRef oContainer;
  454. const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
  455. #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
  456. eStatus = ::ATSFontActivateFromFileReference( &aNewRef,
  457. eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
  458. &oContainer );
  459. #else
  460. FSSpec aFontFSSpec;
  461. eStatus = ::FSGetCatalogInfo( &aNewRef, kFSCatInfoNone,
  462. NULL, NULL, &aFontFSSpec, NULL );
  463. if( eStatus != noErr )
  464. return false;
  465. eStatus = ::ATSFontActivateFromFileSpecification( &aFontFSSpec,
  466. eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
  467. &oContainer );
  468. #endif
  469. if( eStatus != noErr )
  470. return false;
  471. // TODO: ATSFontDeactivate( oContainer ) when fonts are no longer needed
  472. // TODO: register new ImplMacFontdata in pFontList
  473. return true;
  474. }
  475. // -----------------------------------------------------------------------
  476. // callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
  477. struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
  478. static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
  479. {
  480. basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
  481. const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
  482. rPolygon.append( aB2DPoint );
  483. return noErr;
  484. }
  485. static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
  486. const Float32Point* pPoint, void* pData )
  487. {
  488. basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
  489. const sal_uInt32 nPointCount = rPolygon.count();
  490. const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
  491. rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
  492. const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
  493. rPolygon.append( aB2DEndPoint );
  494. const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
  495. rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
  496. return noErr;
  497. }
  498. static OSStatus GgoClosePathProc( void* pData )
  499. {
  500. GgoData* pGgoData = static_cast<GgoData*>(pData);
  501. basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
  502. if( rPolygon.count() > 0 )
  503. pGgoData->mpPolyPoly->append( rPolygon );
  504. rPolygon.clear();
  505. return noErr;
  506. }
  507. static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
  508. {
  509. GgoClosePathProc( pData );
  510. OSStatus eStatus = GgoLineToProc( pPoint, pData );
  511. return eStatus;
  512. }
  513. sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
  514. {
  515. GgoData aGgoData;
  516. aGgoData.mpPolyPoly = &rPolyPoly;
  517. rPolyPoly.clear();
  518. ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback when CWS pdffix02 is integrated
  519. GlyphID aGlyphId = nGlyphId & GF_IDXMASK;
  520. OSStatus eGgoStatus = noErr;
  521. OSStatus eStatus = ATSUGlyphGetCubicPaths( rATSUStyle, aGlyphId,
  522. GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
  523. &aGgoData, &eGgoStatus );
  524. if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
  525. return false;
  526. GgoClosePathProc( &aGgoData );
  527. if( mfFontScale != 1.0 ) {
  528. rPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(+mfFontScale, +mfFontScale));
  529. }
  530. return true;
  531. }
  532. // -----------------------------------------------------------------------
  533. sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect )
  534. {
  535. ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback
  536. GlyphID aGlyphId = nGlyphId & GF_IDXMASK;
  537. ATSGlyphScreenMetrics aGlyphMetrics;
  538. OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
  539. 1, &aGlyphId, 0, FALSE, !mbNonAntialiasedText, &aGlyphMetrics );
  540. if( eStatus != noErr )
  541. return false;
  542. const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale + 0.5);
  543. const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale + 0.5);
  544. const long nWidth = (long)(aGlyphMetrics.width * mfFontScale + 0.5);
  545. const long nHeight = (long)(aGlyphMetrics.height * mfFontScale + 0.5);
  546. Rectangle aRect(Point(nMinX, nMinY), Size(nWidth, nHeight));
  547. if ( mnATSUIRotation == 0 )
  548. rRect = aRect;
  549. else
  550. {
  551. const double fRadians = mnATSUIRotation * (M_PI/0xB40000);
  552. const double nSin = sin( fRadians );
  553. const double nCos = cos( fRadians );
  554. rRect.Left() = nCos*aRect.Left() + nSin*aRect.Top();
  555. rRect.Top() = -nSin*aRect.Left() - nCos*aRect.Top();
  556. rRect.Right() = nCos*aRect.Right() + nSin*aRect.Bottom();
  557. rRect.Bottom() = -nSin*aRect.Right() - nCos*aRect.Bottom();
  558. }
  559. return true;
  560. }
  561. // -----------------------------------------------------------------------
  562. void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
  563. {
  564. // nothing to do since there are no device-specific fonts on Aqua
  565. }
  566. // -----------------------------------------------------------------------
  567. void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
  568. {
  569. }
  570. // -----------------------------------------------------------------------
  571. sal_uInt16 AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
  572. {
  573. if( !pReqFont )
  574. {
  575. ATSUClearStyle( maATSUStyle );
  576. mpMacFontData = NULL;
  577. return 0;
  578. }
  579. // store the requested device font entry
  580. const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
  581. mpMacFontData = pMacFont;
  582. // convert pixel units (as seen by upper layers) to typographic point units
  583. double fScaledAtsHeight = pReqFont->mfExactHeight;
  584. // avoid Fixed16.16 overflows by limiting the ATS font size
  585. static const float fMaxAtsHeight = 144.0;
  586. if( fScaledAtsHeight <= fMaxAtsHeight )
  587. mfFontScale = 1.0;
  588. else
  589. {
  590. mfFontScale = fScaledAtsHeight / fMaxAtsHeight;
  591. fScaledAtsHeight = fMaxAtsHeight;
  592. }
  593. Fixed fFixedSize = FloatToFixed( fScaledAtsHeight );
  594. // enable bold-emulation if needed
  595. Boolean bFakeBold = FALSE;
  596. if( (pReqFont->GetWeight() >= WEIGHT_BOLD)
  597. && (pMacFont->GetWeight() < WEIGHT_SEMIBOLD) )
  598. bFakeBold = TRUE;
  599. // enable italic-emulation if needed
  600. Boolean bFakeItalic = FALSE;
  601. if( ((pReqFont->GetSlant() == ITALIC_NORMAL) || (pReqFont->GetSlant() == ITALIC_OBLIQUE))
  602. && !((pMacFont->GetSlant() == ITALIC_NORMAL) || (pMacFont->GetSlant() == ITALIC_OBLIQUE)) )
  603. bFakeItalic = TRUE;
  604. // enable/disable antialiased text
  605. mbNonAntialiasedText = pReqFont->mbNonAntialiased;
  606. UInt32 nStyleRenderingOptions = kATSStyleNoOptions;
  607. if( pReqFont->mbNonAntialiased )
  608. nStyleRenderingOptions |= kATSStyleNoAntiAliasing;
  609. // set horizontal/vertical mode
  610. ATSUVerticalCharacterType aVerticalCharacterType = kATSUStronglyHorizontal;
  611. if( pReqFont->mbVertical )
  612. aVerticalCharacterType = kATSUStronglyVertical;
  613. // prepare ATS-fontid as type matching to the kATSUFontTag request
  614. ATSUFontID nFontID = static_cast<ATSUFontID>(pMacFont->GetFontId());
  615. // update ATSU style attributes with requested font parameters
  616. // TODO: no need to set styles which are already defaulted
  617. const ATSUAttributeTag aTag[] =
  618. {
  619. kATSUFontTag,
  620. kATSUSizeTag,
  621. kATSUQDBoldfaceTag,
  622. kATSUQDItalicTag,
  623. kATSUStyleRenderingOptionsTag,
  624. kATSUVerticalCharacterTag
  625. };
  626. const ByteCount aValueSize[] =
  627. {
  628. sizeof(ATSUFontID),
  629. sizeof(fFixedSize),
  630. sizeof(bFakeBold),
  631. sizeof(bFakeItalic),
  632. sizeof(nStyleRenderingOptions),
  633. sizeof(aVerticalCharacterType)
  634. };
  635. const ATSUAttributeValuePtr aValue[] =
  636. {
  637. &nFontID,
  638. &fFixedSize,
  639. &bFakeBold,
  640. &bFakeItalic,
  641. &nStyleRenderingOptions,
  642. &aVerticalCharacterType
  643. };
  644. static const int nTagCount = SAL_N_ELEMENTS(aTag);
  645. OSStatus eStatus = ATSUSetAttributes( maATSUStyle, nTagCount,
  646. aTag, aValueSize, aValue );
  647. // reset ATSUstyle if there was an error
  648. if( eStatus != noErr )
  649. {
  650. DBG_WARNING( "AquaSalGraphics::SetFont() : Could not set font attributes!\n");
  651. ATSUClearStyle( maATSUStyle );
  652. mpMacFontData = NULL;
  653. return 0;
  654. }
  655. // prepare font stretching
  656. const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
  657. if( (pReqFont->mnWidth == 0) || (pReqFont->mnWidth == pReqFont->mnHeight) )
  658. {
  659. mfFontStretch = 1.0;
  660. ATSUClearAttributes( maATSUStyle, 1, &aMatrixTag );
  661. }
  662. else
  663. {
  664. mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
  665. CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
  666. const ATSUAttributeValuePtr aAttr = &aMatrix;
  667. const ByteCount aMatrixBytes = sizeof(aMatrix);
  668. eStatus = ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
  669. DBG_ASSERT( (eStatus==noErr), "AquaSalGraphics::SetFont() : Could not set font matrix\n");
  670. }
  671. // prepare font rotation
  672. mnATSUIRotation = FloatToFixed( pReqFont->mnOrientation / 10.0 );
  673. #if OSL_DEBUG_LEVEL > 3
  674. fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
  675. ::rtl::OUStringToOString( pMacFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
  676. ::rtl::OUStringToOString( pMacFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
  677. (int)nFontID,
  678. ::rtl::OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
  679. ::rtl::OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
  680. pReqFont->GetWeight(),
  681. pReqFont->GetSlant(),
  682. pReqFont->mnHeight,
  683. pReqFont->mnWidth,
  684. pReqFont->mnOrientation);
  685. #endif
  686. return 0;
  687. }
  688. // -----------------------------------------------------------------------
  689. const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
  690. {
  691. if( !mpMacFontData )
  692. return ImplFontCharMap::GetDefaultMap();
  693. return mpMacFontData->GetImplFontCharMap();
  694. }
  695. bool AquaSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
  696. {
  697. if( !mpMacFontData )
  698. return false;
  699. return mpMacFontData->GetImplFontCapabilities(rFontCapabilities);
  700. }
  701. // -----------------------------------------------------------------------
  702. // fake a SFNT font directory entry for a font table
  703. // see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
  704. static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen,
  705. const unsigned char* /*pData*/, unsigned char*& rpDest )
  706. {
  707. // write entry tag
  708. rpDest[ 0] = (char)(eFCC >> 24);
  709. rpDest[ 1] = (char)(eFCC >> 16);
  710. rpDest[ 2] = (char)(eFCC >> 8);
  711. rpDest[ 3] = (char)(eFCC >> 0);
  712. // TODO: get entry checksum and write it
  713. // not too important since the subsetter doesn't care currently
  714. // for( pData+nOfs ... pData+nOfs+nLen )
  715. // write entry offset
  716. rpDest[ 8] = (char)(nOfs >> 24);
  717. rpDest[ 9] = (char)(nOfs >> 16);
  718. rpDest[10] = (char)(nOfs >> 8);
  719. rpDest[11] = (char)(nOfs >> 0);
  720. // write entry length
  721. rpDest[12] = (char)(nLen >> 24);
  722. rpDest[13] = (char)(nLen >> 16);
  723. rpDest[14] = (char)(nLen >> 8);
  724. rpDest[15] = (char)(nLen >> 0);
  725. // advance to next entry
  726. rpDest += 16;
  727. }
  728. bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData,
  729. ByteVector& rBuffer, bool* pJustCFF )
  730. {
  731. const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
  732. const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId());
  733. ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId );
  734. ByteCount nCffLen = 0;
  735. OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen);
  736. if( pJustCFF != NULL )
  737. {
  738. *pJustCFF = (eStatus == noErr) && (nCffLen > 0);
  739. if( *pJustCFF )
  740. {
  741. rBuffer.resize( nCffLen );
  742. eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen);
  743. if( (eStatus != noErr) || (nCffLen <= 0) )
  744. return false;
  745. return true;
  746. }
  747. }
  748. // get font table availability and size in bytes
  749. ByteCount nHeadLen = 0;
  750. eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
  751. if( (eStatus != noErr) || (nHeadLen <= 0) )
  752. return false;
  753. ByteCount nMaxpLen = 0;
  754. eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, 0, NULL, &nMaxpLen);
  755. if( (eStatus != noErr) || (nMaxpLen <= 0) )
  756. return false;
  757. ByteCount nCmapLen = 0;
  758. eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen);
  759. if( (eStatus != noErr) || (nCmapLen <= 0) )
  760. return false;
  761. ByteCount nNameLen = 0;
  762. eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen);
  763. if( (eStatus != noErr) || (nNameLen <= 0) )
  764. return false;
  765. ByteCount nHheaLen = 0;
  766. eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, 0, NULL, &nHheaLen);
  767. if( (eStatus != noErr) || (nHheaLen <= 0) )
  768. return false;
  769. ByteCount nHmtxLen = 0;
  770. eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, 0, NULL, &nHmtxLen);
  771. if( (eStatus != noErr) || (nHmtxLen <= 0) )
  772. return false;
  773. // get the glyph outline tables
  774. ByteCount nLocaLen = 0;
  775. ByteCount nGlyfLen = 0;
  776. if( (eStatus != noErr) || (nCffLen <= 0) )
  777. {
  778. eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
  779. if( (eStatus != noErr) || (nLocaLen <= 0) )
  780. return false;
  781. eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
  782. if( (eStatus != noErr) || (nGlyfLen <= 0) )
  783. return false;
  784. }
  785. ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0;
  786. if( nGlyfLen ) // TODO: reduce PDF size by making hint subsetting optional
  787. {
  788. eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen);
  789. eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen);
  790. eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, 0, NULL, &nFpgmLen);
  791. }
  792. // prepare a byte buffer for a fake font
  793. int nTableCount = 7;
  794. nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0);
  795. const ByteCount nFdirLen = 12 + 16*nTableCount;
  796. ByteCount nTotalLen = nFdirLen;
  797. nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen;
  798. if( nGlyfLen )
  799. nTotalLen += nLocaLen + nGlyfLen;
  800. else
  801. nTotalLen += nCffLen;
  802. nTotalLen += nHheaLen + nHmtxLen;
  803. nTotalLen += nPrepLen + nCvtLen + nFpgmLen;
  804. rBuffer.resize( nTotalLen );
  805. // fake a SFNT font directory header
  806. if( nTableCount < 16 )
  807. {
  808. int nLog2 = 0;
  809. while( (nTableCount >> nLog2) > 1 ) ++nLog2;
  810. rBuffer[ 1] = 1; // Win-TTF style scaler
  811. rBuffer[ 5] = nTableCount; // table count
  812. rBuffer[ 7] = nLog2*16; // searchRange
  813. rBuffer[ 9] = nLog2; // entrySelector
  814. rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
  815. }
  816. // get font table raw data and update the fake directory entries
  817. ByteCount nOfs = nFdirLen;
  818. unsigned char* pFakeEntry = &rBuffer[12];
  819. eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nCmapLen, (void*)&rBuffer[nOfs], &nCmapLen);
  820. FakeDirEntry( GetTag("cmap"), nOfs, nCmapLen, &rBuffer[0], pFakeEntry );
  821. nOfs += nCmapLen;
  822. if( nCvtLen ) {
  823. eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, nCvtLen, (void*)&rBuffer[nOfs], &nCvtLen);
  824. FakeDirEntry( GetTag("cvt "), nOfs, nCvtLen, &rBuffer[0], pFakeEntry );
  825. nOfs += nCvtLen;
  826. }
  827. if( nFpgmLen ) {
  828. eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, nFpgmLen, (void*)&rBuffer[nOfs], &nFpgmLen);
  829. FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry );
  830. nOfs += nFpgmLen;
  831. }
  832. if( nCffLen ) {
  833. eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen);
  834. FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry );
  835. nOfs += nGlyfLen;
  836. } else {
  837. eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
  838. FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
  839. nOfs += nGlyfLen;
  840. eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
  841. FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
  842. nOfs += nLocaLen;
  843. }
  844. eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen);
  845. FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry );
  846. nOfs += nHeadLen;
  847. eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, nHheaLen, (void*)&rBuffer[nOfs], &nHheaLen);
  848. FakeDirEntry( GetTag("hhea"), nOfs, nHheaLen, &rBuffer[0], pFakeEntry );
  849. nOfs += nHheaLen;
  850. eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen);
  851. FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry );
  852. nOfs += nHmtxLen;
  853. eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen);
  854. FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry );
  855. nOfs += nMaxpLen;
  856. eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, nNameLen, (void*)&rBuffer[nOfs], &nNameLen);
  857. FakeDirEntry( GetTag("name"), nOfs, nNameLen, &rBuffer[0], pFakeEntry );
  858. nOfs += nNameLen;
  859. if( nPrepLen ) {
  860. eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, nPrepLen, (void*)&rBuffer[nOfs], &nPrepLen);
  861. FakeDirEntry( GetTag("prep"), nOfs, nPrepLen, &rBuffer[0], pFakeEntry );
  862. nOfs += nPrepLen;
  863. }
  864. DBG_ASSERT( (nOfs==nTotalLen), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalLen)");
  865. return sal_True;
  866. }
  867. // -----------------------------------------------------------------------
  868. void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
  869. Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
  870. {
  871. rGlyphWidths.clear();
  872. rUnicodeEnc.clear();
  873. if( pFontData->IsSubsettable() )
  874. {
  875. ByteVector aBuffer;
  876. if( !GetRawFontData( pFontData, aBuffer, NULL ) )
  877. return;
  878. // TODO: modernize psprint's horrible fontsubset C-API
  879. // this probably only makes sense after the switch to another SCM
  880. // that can preserve change history after file renames
  881. // use the font subsetter to get the widths
  882. TrueTypeFont* pSftFont = NULL;
  883. int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
  884. if( nRC != SF_OK )
  885. return;
  886. const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
  887. if( nGlyphCount > 0 )
  888. {
  889. // get glyph metrics
  890. rGlyphWidths.resize(nGlyphCount);
  891. std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
  892. for( int i = 0; i < nGlyphCount; i++ )
  893. aGlyphIds[i] = static_cast<sal_uInt16>(i);
  894. const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
  895. pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
  896. if( pGlyphMetrics )
  897. {
  898. for( int i = 0; i < nGlyphCount; ++i )
  899. rGlyphWidths[i] = pGlyphMetrics[i].adv;
  900. free( (void*)pGlyphMetrics );
  901. }
  902. const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
  903. DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
  904. pMap->AddReference(); // TODO: add and use RAII object instead
  905. // get unicode<->glyph encoding
  906. // TODO? avoid sft mapping by using the pMap itself
  907. int nCharCount = pMap->GetCharCount();
  908. sal_uInt32 nChar = pMap->GetFirstChar();
  909. for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
  910. {
  911. if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
  912. break;
  913. sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
  914. sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
  915. if( nGlyph > 0 )
  916. rUnicodeEnc[ nUcsChar ] = nGlyph;
  917. }
  918. pMap->DeReference(); // TODO: add and use RAII object instead
  919. }
  920. ::CloseTTFont( pSftFont );
  921. }
  922. else if( pFontData->IsEmbeddable() )
  923. {
  924. // get individual character widths
  925. OSL_FAIL("not implemented for non-subsettable fonts!\n");
  926. }
  927. }
  928. // -----------------------------------------------------------------------
  929. const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
  930. const PhysicalFontFace*, const Ucs2OStrMap** /*ppNonEncoded*/ )
  931. {
  932. return NULL;
  933. }
  934. // -----------------------------------------------------------------------
  935. const void* AquaSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
  936. const sal_Ucs* /*pUnicodes*/,
  937. sal_Int32* /*pWidths*/,
  938. FontSubsetInfo&,
  939. long* /*pDataLen*/ )
  940. {
  941. return NULL;
  942. }
  943. // -----------------------------------------------------------------------
  944. void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
  945. {
  946. // TODO: implementing this only makes sense when the implementation of
  947. // AquaSalGraphics::GetEmbedFontData() returns non-NULL
  948. (void)pData;
  949. DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
  950. }
  951. // -----------------------------------------------------------------------
  952. SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
  953. {
  954. SystemFontData aSysFontData;
  955. OSStatus err;
  956. aSysFontData.nSize = sizeof( SystemFontData );
  957. // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks.
  958. ATSUFontID fontId;
  959. err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 );
  960. if (err) fontId = 0;
  961. aSysFontData.aATSUFontID = (void *) fontId;
  962. Boolean bFbold;
  963. err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 );
  964. if (err) bFbold = FALSE;
  965. aSysFontData.bFakeBold = (bool) bFbold;
  966. Boolean bFItalic;
  967. err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 );
  968. if (err) bFItalic = FALSE;
  969. aSysFontData.bFakeItalic = (bool) bFItalic;
  970. ATSUVerticalCharacterType aVerticalCharacterType;
  971. err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 );
  972. if (!err && aVerticalCharacterType == kATSUStronglyVertical) {
  973. aSysFontData.bVerticalCharacterType = true;
  974. } else {
  975. aSysFontData.bVerticalCharacterType = false;
  976. }
  977. aSysFontData.bAntialias = !mbNonAntialiasedText;
  978. return aSysFontData;
  979. }
  980. // -----------------------------------------------------------------------
  981. /* vim:set shiftwidth=4 softtabstop=4 expandtab: */