1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <config_folders.h>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/range/b2drectangle.hxx>
28 #include <osl/file.hxx>
29 #include <osl/mutex.hxx>
30 #include <osl/process.h>
31 #include <rtl/bootstrap.h>
32 #include <rtl/strbuf.hxx>
34 #include <vcl/metric.hxx>
35 #include <vcl/fontcharmap.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/sysdata.hxx>
39 #include "quartz/ctfonts.hxx"
40 #include "fontsubset.hxx"
41 #include "impfont.hxx"
42 #include "impfontcharmap.hxx"
43 #include "impfontmetricdata.hxx"
44 #include "CommonSalLayout.hxx"
46 #include "PhysicalFontCollection.hxx"
49 #include "osx/salframe.h"
51 #include "quartz/utils.h"
53 #include "saldatabasic.hxx"
55 #include "sallayout.hxx"
60 class CoreTextGlyphFallbackSubstititution
61 : public ImplGlyphFallbackFontSubstitution
64 bool FindFontSubstitute(FontSelectPattern
&, OUString
&) const override
;
67 bool CoreTextGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern
& rPattern
,
68 OUString
& rMissingChars
) const
71 CoreTextStyle
rStyle(rPattern
);
72 CTFontRef pFont
= static_cast<CTFontRef
>(CFDictionaryGetValue(rStyle
.GetStyleDict(), kCTFontAttributeName
));
73 CFStringRef pStr
= CreateCFString(rMissingChars
);
76 CTFontRef pFallback
= CTFontCreateForString(pFont
, pStr
, CFRangeMake(0, CFStringGetLength(pStr
)));
81 CTFontDescriptorRef pDesc
= CTFontCopyFontDescriptor(pFallback
);
82 FontAttributes rAttr
= DevFontFromCTFontDescriptor(pDesc
, nullptr);
84 rPattern
.maSearchName
= rAttr
.GetFamilyName();
86 rPattern
.SetWeight(rAttr
.GetWeight());
87 rPattern
.SetItalic(rAttr
.GetItalic());
88 rPattern
.SetPitch(rAttr
.GetPitch());
89 rPattern
.SetWidthType(rAttr
.GetWidthType());
91 SalData
* pSalData
= GetSalData();
92 if (pSalData
->mpFontList
)
93 rPattern
.mpFontData
= pSalData
->mpFontList
->GetFontDataFromId(reinterpret_cast<sal_IntPtr
>(pDesc
));
104 CoreTextFontFace::CoreTextFontFace( const CoreTextFontFace
& rSrc
)
105 : PhysicalFontFace( rSrc
)
106 , mnFontId( rSrc
.mnFontId
)
108 if( rSrc
.mxCharMap
.is() )
109 mxCharMap
= rSrc
.mxCharMap
;
112 CoreTextFontFace::CoreTextFontFace( const FontAttributes
& rDFA
, sal_IntPtr nFontId
)
113 : PhysicalFontFace( rDFA
)
114 , mnFontId( nFontId
)
115 , mbFontCapabilitiesRead( false )
119 CoreTextFontFace::~CoreTextFontFace()
123 sal_IntPtr
CoreTextFontFace::GetFontId() const
125 return (sal_IntPtr
)mnFontId
;
128 const FontCharMapRef
CoreTextFontFace::GetFontCharMap() const
130 // return the cached charmap
134 // set the default charmap
135 FontCharMapRef
pCharMap( new FontCharMap() );
136 mxCharMap
= pCharMap
;
138 // get the CMAP byte size
139 // allocate a buffer for the CMAP raw data
140 const int nBufSize
= GetFontTable( "cmap", nullptr );
141 SAL_WARN_IF( (nBufSize
<= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable1 failed!");
145 // get the CMAP raw data
146 std::vector
<unsigned char> aBuffer( nBufSize
);
147 const int nRawLength
= GetFontTable( "cmap", &aBuffer
[0] );
148 SAL_WARN_IF( (nRawLength
<= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable2 failed!");
149 if( nRawLength
<= 0 )
152 SAL_WARN_IF( (nBufSize
!=nRawLength
), "vcl", "CoreTextFontFace::GetFontCharMap : ByteCount mismatch!");
155 CmapResult aCmapResult
;
156 if( ParseCMAP( &aBuffer
[0], nRawLength
, aCmapResult
) )
158 FontCharMapRef
xDefFontCharMap( new FontCharMap(aCmapResult
) );
159 // create the matching charmap
160 mxCharMap
= xDefFontCharMap
;
166 bool CoreTextFontFace::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
168 // read this only once per font
169 if( mbFontCapabilitiesRead
)
171 rFontCapabilities
= maFontCapabilities
;
172 return rFontCapabilities
.oUnicodeRange
|| rFontCapabilities
.oCodePageRange
;
174 mbFontCapabilitiesRead
= true;
176 int nBufSize
= GetFontTable( "OS/2", nullptr );
179 // allocate a buffer for the OS/2 raw data
180 std::vector
<unsigned char> aBuffer( nBufSize
);
181 // get the OS/2 raw data
182 const int nRawLength
= GetFontTable( "OS/2", &aBuffer
[0] );
185 const unsigned char* pOS2Table
= &aBuffer
[0];
186 vcl::getTTCoverage( maFontCapabilities
.oUnicodeRange
,
187 maFontCapabilities
.oCodePageRange
,
188 pOS2Table
, nRawLength
);
191 rFontCapabilities
= maFontCapabilities
;
192 return rFontCapabilities
.oUnicodeRange
|| rFontCapabilities
.oCodePageRange
;
195 AquaSalGraphics::AquaSalGraphics()
197 , mrContext( nullptr )
201 #if OSL_DEBUG_LEVEL > 0
202 , mnContextStackDepth( 0 )
204 , mpXorEmulation( nullptr )
211 , mxClipPath( nullptr )
212 , maLineColor( COL_WHITE
)
213 , maFillColor( COL_BLACK
)
214 , maTextColor( COL_BLACK
)
215 , mbNonAntialiasedText( false )
221 , mbForeignContext( false )
224 SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this );
226 for (int i
= 0; i
< MAX_FALLBACK
; ++i
)
228 mpTextStyle
[i
] = nullptr;
229 mpFontData
[i
] = nullptr;
233 AquaSalGraphics::~AquaSalGraphics()
235 SAL_INFO( "vcl.quartz", "AquaSalGraphics::~AquaSalGraphics() this=" << this );
239 SAL_INFO("vcl.cg", "CGPathRelease(" << mxClipPath
<< ")" );
240 CGPathRelease( mxClipPath
);
243 for (int i
= 0; i
< MAX_FALLBACK
; ++i
)
244 delete mpTextStyle
[i
];
247 delete mpXorEmulation
;
250 if (mbForeignContext
)
255 SAL_INFO("vcl.cg", "CGLayerRelease(" << mxLayer
<< ")" );
256 CGLayerRelease( mxLayer
);
264 // destroy backbuffer bitmap context that we created ourself
265 SAL_INFO("vcl.cg", "CGContextRelease(" << mrContext
<< ")" );
266 CGContextRelease( mrContext
);
271 SalGraphicsImpl
* AquaSalGraphics::GetImpl() const
276 void AquaSalGraphics::SetTextColor( SalColor nSalColor
)
278 maTextColor
= RGBAColor( nSalColor
);
279 // SAL_ DEBUG(std::hex << nSalColor << std::dec << "={" << maTextColor.GetRed() << ", " << maTextColor.GetGreen() << ", " << maTextColor.GetBlue() << ", " << maTextColor.GetAlpha() << "}");
282 void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef
& rxFontMetric
, int nFallbackLevel
)
284 if (nFallbackLevel
< MAX_FALLBACK
&& mpTextStyle
[nFallbackLevel
])
286 mpTextStyle
[nFallbackLevel
]->GetFontMetric(rxFontMetric
);
290 static bool AddTempDevFont(const OUString
& rFontFileURL
)
292 OUString aUSytemPath
;
293 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
294 OString aCFileName
= OUStringToOString( aUSytemPath
, RTL_TEXTENCODING_UTF8
);
296 CFStringRef rFontPath
= CFStringCreateWithCString(nullptr, aCFileName
.getStr(), kCFStringEncodingUTF8
);
297 CFURLRef rFontURL
= CFURLCreateWithFileSystemPath(nullptr, rFontPath
, kCFURLPOSIXPathStyle
, true);
300 bool success
= CTFontManagerRegisterFontsForURL(rFontURL
, kCTFontManagerScopeProcess
, &error
);
305 CFRelease(rFontPath
);
311 static void AddTempFontDir( const OUString
&rFontDirUrl
)
313 osl::Directory
aFontDir( rFontDirUrl
);
314 osl::FileBase::RC rcOSL
= aFontDir
.open();
315 if( rcOSL
== osl::FileBase::E_None
)
317 osl::DirectoryItem aDirItem
;
319 while( aFontDir
.getNextItem( aDirItem
, 10 ) == osl::FileBase::E_None
)
321 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileURL
);
322 rcOSL
= aDirItem
.getFileStatus( aFileStatus
);
323 if ( rcOSL
== osl::FileBase::E_None
)
325 AddTempDevFont(aFileStatus
.getFileURL());
331 static void AddLocalTempFontDirs()
333 static bool bFirst
= true;
339 // add private font files
341 OUString
aBrandStr( "$BRAND_BASE_DIR" );
342 rtl_bootstrap_expandMacros( &aBrandStr
.pData
);
343 AddTempFontDir( aBrandStr
+ "/" LIBO_SHARE_FOLDER
"/fonts/truetype/" );
346 void AquaSalGraphics::GetDevFontList( PhysicalFontCollection
* pFontCollection
)
348 SAL_WARN_IF( !pFontCollection
, "vcl", "AquaSalGraphics::GetDevFontList(NULL) !");
350 AddLocalTempFontDirs();
352 // The idea is to cache the list of system fonts once it has been generated.
353 // SalData seems to be a good place for this caching. However we have to
354 // carefully make the access to the font list thread-safe. If we register
355 // a font-change event handler to update the font list in case fonts have
356 // changed on the system we have to lock access to the list. The right
357 // way to do that is the solar mutex since GetDevFontList is protected
358 // through it as should be all event handlers
360 SalData
* pSalData
= GetSalData();
361 if( !pSalData
->mpFontList
)
362 pSalData
->mpFontList
= GetCoretextFontList();
364 // Copy all PhysicalFontFace objects contained in the SystemFontList
365 pSalData
->mpFontList
->AnnounceFonts( *pFontCollection
);
367 static CoreTextGlyphFallbackSubstititution aSubstFallback
;
368 pFontCollection
->SetFallbackHook(&aSubstFallback
);
371 void AquaSalGraphics::ClearDevFontCache()
373 SalData
* pSalData
= GetSalData();
374 delete pSalData
->mpFontList
;
375 pSalData
->mpFontList
= nullptr;
378 bool AquaSalGraphics::AddTempDevFont( PhysicalFontCollection
*,
379 const OUString
& rFontFileURL
, const OUString
& /*rFontName*/ )
381 return ::AddTempDevFont(rFontFileURL
);
384 bool AquaSalGraphics::GetGlyphOutline(const GlyphItem
& rGlyph
, basegfx::B2DPolyPolygon
& rPolyPoly
)
386 const int nFallbackLevel
= rGlyph
.mnFallbackLevel
;
387 if (nFallbackLevel
< MAX_FALLBACK
&& mpTextStyle
[nFallbackLevel
])
389 const bool bRC
= mpTextStyle
[nFallbackLevel
]->GetGlyphOutline(rGlyph
, rPolyPoly
);
395 bool AquaSalGraphics::GetGlyphBoundRect(const GlyphItem
& rGlyph
, tools::Rectangle
& rRect
)
397 const int nFallbackLevel
= rGlyph
.mnFallbackLevel
;
398 if (nFallbackLevel
< MAX_FALLBACK
&& mpTextStyle
[nFallbackLevel
])
400 const bool bRC
= mpTextStyle
[nFallbackLevel
]->GetGlyphBoundRect(rGlyph
, rRect
);
406 void AquaSalGraphics::DrawTextLayout(const CommonSalLayout
& rLayout
)
408 const CoreTextStyle
& rStyle
= rLayout
.getFontData();
409 const FontSelectPattern
& rFontSelect
= rStyle
.maFontSelData
;
410 if (rFontSelect
.mnHeight
== 0)
413 CTFontRef pFont
= static_cast<CTFontRef
>(CFDictionaryGetValue(rStyle
.GetStyleDict(), kCTFontAttributeName
));
414 CGAffineTransform aRotMatrix
= CGAffineTransformMakeRotation(-rStyle
.mfFontRotation
);
417 const GlyphItem
* pGlyph
;
418 std::vector
<CGGlyph
> aGlyphIds
;
419 std::vector
<CGPoint
> aGlyphPos
;
420 std::vector
<bool> aGlyphOrientation
;
422 while (rLayout
.GetNextGlyphs(1, &pGlyph
, aPos
, nStart
))
424 CGPoint aGCPos
= CGPointMake(aPos
.X(), -aPos
.Y());
426 // Whether the glyph should be upright in vertical mode or not
427 bool bUprightGlyph
= false;
429 if (rStyle
.mfFontRotation
)
431 if (pGlyph
->IsVertical())
433 bUprightGlyph
= true;
434 // Adjust the position of upright (vertical) glyphs.
435 aGCPos
.y
-= CTFontGetAscent(pFont
) - CTFontGetDescent(pFont
);
439 // Transform the position of rotated glyphs.
440 aGCPos
= CGPointApplyAffineTransform(aGCPos
, aRotMatrix
);
444 aGlyphIds
.push_back(pGlyph
->maGlyphId
);
445 aGlyphPos
.push_back(aGCPos
);
446 aGlyphOrientation
.push_back(bUprightGlyph
);
449 if (aGlyphIds
.empty())
452 CGContextSaveGState(mrContext
);
454 // The view is vertically flipped (no idea why), flip it back.
455 CGContextScaleCTM(mrContext
, 1.0, -1.0);
456 CGContextSetShouldAntialias(mrContext
, !mbNonAntialiasedText
);
457 CGContextSetFillColor(mrContext
, maTextColor
.AsArray());
459 auto aIt
= aGlyphOrientation
.cbegin();
460 while (aIt
!= aGlyphOrientation
.cend())
462 bool bUprightGlyph
= *aIt
;
463 // Find the boundary of the run of glyphs with the same rotation, to be
465 auto aNext
= std::find(aIt
, aGlyphOrientation
.cend(), !bUprightGlyph
);
466 size_t nStartIndex
= std::distance(aGlyphOrientation
.cbegin(), aIt
);
467 size_t nLen
= std::distance(aIt
, aNext
);
469 CGContextSaveGState(mrContext
);
470 if (rStyle
.mfFontRotation
&& !bUprightGlyph
)
471 CGContextRotateCTM(mrContext
, rStyle
.mfFontRotation
);
472 CTFontDrawGlyphs(pFont
, &aGlyphIds
[nStartIndex
], &aGlyphPos
[nStartIndex
], nLen
, mrContext
);
473 CGContextRestoreGState(mrContext
);
478 CGContextRestoreGState(mrContext
);
481 void AquaSalGraphics::SetFont(FontSelectPattern
* pReqFont
, int nFallbackLevel
)
483 // release the text style
484 for (int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
486 delete mpTextStyle
[i
];
487 mpTextStyle
[i
] = nullptr;
490 // handle NULL request meaning: release-font-resources request
493 mpFontData
[nFallbackLevel
] = nullptr;
497 // update the text style
498 mpFontData
[nFallbackLevel
] = static_cast<const CoreTextFontFace
*>(pReqFont
->mpFontData
);
499 mpTextStyle
[nFallbackLevel
] = new CoreTextStyle(*pReqFont
);
503 " to " << mpFontData
[nFallbackLevel
]->GetFamilyName()
504 << ", " << mpFontData
[nFallbackLevel
]->GetStyleName()
505 << " fontid=" << mpFontData
[nFallbackLevel
]->GetFontId()
506 << " for " << pReqFont
->GetFamilyName()
507 << ", " << pReqFont
->GetStyleName()
508 << " weight=" << pReqFont
->GetWeight()
509 << " slant=" << pReqFont
->GetItalic()
510 << " size=" << pReqFont
->mnHeight
<< "x" << pReqFont
->mnWidth
511 << " orientation=" << pReqFont
->mnOrientation
512 << " fallback level " << nFallbackLevel
516 SalLayout
* AquaSalGraphics::GetTextLayout(ImplLayoutArgs
& /*rArgs*/, int nFallbackLevel
)
518 if (mpTextStyle
[nFallbackLevel
])
519 return new CommonSalLayout(*mpTextStyle
[nFallbackLevel
]);
524 const FontCharMapRef
AquaSalGraphics::GetFontCharMap() const
528 FontCharMapRef
xFontCharMap( new FontCharMap() );
532 return mpFontData
[0]->GetFontCharMap();
535 bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
540 return mpFontData
[0]->GetFontCapabilities(rFontCapabilities
);
543 // fake a SFNT font directory entry for a font table
544 // see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html#Directory
545 static void FakeDirEntry( const char aTag
[5], ByteCount nOfs
, ByteCount nLen
,
546 const unsigned char* /*pData*/, unsigned char*& rpDest
)
549 rpDest
[ 0] = aTag
[0];
550 rpDest
[ 1] = aTag
[1];
551 rpDest
[ 2] = aTag
[2];
552 rpDest
[ 3] = aTag
[3];
553 // TODO: get entry checksum and write it
554 // not too important since the subsetter doesn't care currently
555 // for( pData+nOfs ... pData+nOfs+nLen )
556 // write entry offset
557 rpDest
[ 8] = (char)(nOfs
>> 24);
558 rpDest
[ 9] = (char)(nOfs
>> 16);
559 rpDest
[10] = (char)(nOfs
>> 8);
560 rpDest
[11] = (char)(nOfs
>> 0);
561 // write entry length
562 rpDest
[12] = (char)(nLen
>> 24);
563 rpDest
[13] = (char)(nLen
>> 16);
564 rpDest
[14] = (char)(nLen
>> 8);
565 rpDest
[15] = (char)(nLen
>> 0);
566 // advance to next entry
570 // fake a TTF or CFF font as directly accessing font file is not possible
571 // when only the fontid is known. This approach also handles *.font fonts.
572 bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace
* pFontData
,
573 std::vector
<unsigned char>& rBuffer
, bool* pJustCFF
)
575 const CoreTextFontFace
* pMacFont
= static_cast<const CoreTextFontFace
*>(pFontData
);
577 // short circuit for CFF-only fonts
578 const int nCffSize
= pMacFont
->GetFontTable( "CFF ", nullptr);
579 if( pJustCFF
!= nullptr )
581 *pJustCFF
= (nCffSize
> 0);
584 rBuffer
.resize( nCffSize
);
585 const int nCffRead
= pMacFont
->GetFontTable( "CFF ", &rBuffer
[0]);
586 if( nCffRead
!= nCffSize
)
594 // get font table availability and size in bytes
595 const int nHeadSize
= pMacFont
->GetFontTable( "head", nullptr);
599 const int nMaxpSize
= pMacFont
->GetFontTable( "maxp", nullptr);
603 const int nCmapSize
= pMacFont
->GetFontTable( "cmap", nullptr);
607 const int nNameSize
= pMacFont
->GetFontTable( "name", nullptr);
611 const int nHheaSize
= pMacFont
->GetFontTable( "hhea", nullptr);
615 const int nHmtxSize
= pMacFont
->GetFontTable( "hmtx", nullptr);
619 // get the ttf-glyf outline tables
624 nLocaSize
= pMacFont
->GetFontTable( "loca", nullptr);
628 nGlyfSize
= pMacFont
->GetFontTable( "glyf", nullptr);
633 int nPrepSize
= 0, nCvtSize
= 0, nFpgmSize
= 0;
634 if( nGlyfSize
) // TODO: reduce PDF size by making hint subsetting optional
636 nPrepSize
= pMacFont
->GetFontTable( "prep", nullptr);
637 nCvtSize
= pMacFont
->GetFontTable( "cvt ", nullptr);
638 nFpgmSize
= pMacFont
->GetFontTable( "fpgm", nullptr);
641 // prepare a byte buffer for a fake font
643 nTableCount
+= (nPrepSize
>0?1:0) + (nCvtSize
>0?1:0) + (nFpgmSize
>0?1:0) + (nGlyfSize
>0?1:0);
644 const ByteCount nFdirSize
= 12 + 16*nTableCount
;
645 ByteCount nTotalSize
= nFdirSize
;
646 nTotalSize
+= nHeadSize
+ nMaxpSize
+ nNameSize
+ nCmapSize
;
650 nTotalSize
+= nLocaSize
+ nGlyfSize
;
654 nTotalSize
+= nCffSize
;
656 nTotalSize
+= nHheaSize
+ nHmtxSize
;
657 nTotalSize
+= nPrepSize
+ nCvtSize
+ nFpgmSize
;
658 rBuffer
.resize( nTotalSize
);
660 // fake a SFNT font directory header
661 if( nTableCount
< 16 )
664 while( (nTableCount
>> nLog2
) > 1 ) ++nLog2
;
665 rBuffer
[ 1] = 1; // Win-TTF style scaler
666 rBuffer
[ 5] = nTableCount
; // table count
667 rBuffer
[ 7] = nLog2
*16; // searchRange
668 rBuffer
[ 9] = nLog2
; // entrySelector
669 rBuffer
[11] = (nTableCount
-nLog2
)*16; // rangeShift
672 // get font table raw data and update the fake directory entries
673 ByteCount nOfs
= nFdirSize
;
674 unsigned char* pFakeEntry
= &rBuffer
[12];
675 if( nCmapSize
!= pMacFont
->GetFontTable( "cmap", &rBuffer
[nOfs
]))
678 FakeDirEntry( "cmap", nOfs
, nCmapSize
, &rBuffer
[0], pFakeEntry
);
682 if( nCvtSize
!= pMacFont
->GetFontTable( "cvt ", &rBuffer
[nOfs
]))
685 FakeDirEntry( "cvt ", nOfs
, nCvtSize
, &rBuffer
[0], pFakeEntry
);
690 if( nFpgmSize
!= pMacFont
->GetFontTable( "fpgm", &rBuffer
[nOfs
]))
693 FakeDirEntry( "fpgm", nOfs
, nFpgmSize
, &rBuffer
[0], pFakeEntry
);
698 if( nCffSize
!= pMacFont
->GetFontTable( "CFF ", &rBuffer
[nOfs
]))
701 FakeDirEntry( "CFF ", nOfs
, nCffSize
, &rBuffer
[0], pFakeEntry
);
706 if( nGlyfSize
!= pMacFont
->GetFontTable( "glyf", &rBuffer
[nOfs
]))
709 FakeDirEntry( "glyf", nOfs
, nGlyfSize
, &rBuffer
[0], pFakeEntry
);
712 if( nLocaSize
!= pMacFont
->GetFontTable( "loca", &rBuffer
[nOfs
]))
715 FakeDirEntry( "loca", nOfs
, nLocaSize
, &rBuffer
[0], pFakeEntry
);
718 if( nHeadSize
!= pMacFont
->GetFontTable( "head", &rBuffer
[nOfs
]))
721 FakeDirEntry( "head", nOfs
, nHeadSize
, &rBuffer
[0], pFakeEntry
);
724 if( nHheaSize
!= pMacFont
->GetFontTable( "hhea", &rBuffer
[nOfs
]))
727 FakeDirEntry( "hhea", nOfs
, nHheaSize
, &rBuffer
[0], pFakeEntry
);
729 if( nHmtxSize
!= pMacFont
->GetFontTable( "hmtx", &rBuffer
[nOfs
]))
732 FakeDirEntry( "hmtx", nOfs
, nHmtxSize
, &rBuffer
[0], pFakeEntry
);
734 if( nMaxpSize
!= pMacFont
->GetFontTable( "maxp", &rBuffer
[nOfs
]))
737 FakeDirEntry( "maxp", nOfs
, nMaxpSize
, &rBuffer
[0], pFakeEntry
);
739 if( nNameSize
!= pMacFont
->GetFontTable( "name", &rBuffer
[nOfs
]))
742 FakeDirEntry( "name", nOfs
, nNameSize
, &rBuffer
[0], pFakeEntry
);
746 if( nPrepSize
!= pMacFont
->GetFontTable( "prep", &rBuffer
[nOfs
]))
749 FakeDirEntry( "prep", nOfs
, nPrepSize
, &rBuffer
[0], pFakeEntry
);
753 SAL_WARN_IF( (nOfs
!=nTotalSize
), "vcl", "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
758 void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFontData
, bool bVertical
,
759 std::vector
< sal_Int32
>& rGlyphWidths
, Ucs2UIntMap
& rUnicodeEnc
)
761 rGlyphWidths
.clear();
764 std::vector
<unsigned char> aBuffer
;
765 if( !GetRawFontData( pFontData
, aBuffer
, nullptr ) )
768 // TODO: modernize psprint's horrible fontsubset C-API
769 // this probably only makes sense after the switch to another SCM
770 // that can preserve change history after file renames
772 // use the font subsetter to get the widths
773 TrueTypeFont
* pSftFont
= nullptr;
774 int nRC
= ::OpenTTFontBuffer( static_cast<void*>(&aBuffer
[0]), aBuffer
.size(), 0, &pSftFont
);
778 const int nGlyphCount
= ::GetTTGlyphCount( pSftFont
);
779 if( nGlyphCount
> 0 )
782 rGlyphWidths
.resize(nGlyphCount
);
783 std::vector
<sal_uInt16
> aGlyphIds(nGlyphCount
);
784 for( int i
= 0; i
< nGlyphCount
; i
++ )
786 aGlyphIds
[i
] = static_cast<sal_uInt16
>(i
);
789 const TTSimpleGlyphMetrics
* pGlyphMetrics
= ::GetTTSimpleGlyphMetrics( pSftFont
, &aGlyphIds
[0],
790 nGlyphCount
, bVertical
);
793 for( int i
= 0; i
< nGlyphCount
; ++i
)
795 rGlyphWidths
[i
] = pGlyphMetrics
[i
].adv
;
797 free( const_cast<TTSimpleGlyphMetrics
*>(pGlyphMetrics
) );
800 CoreTextFontFace
rCTFontData(*pFontData
, pFontData
->GetFontId());
801 FontCharMapRef xFCMap
= rCTFontData
.GetFontCharMap();
802 SAL_WARN_IF( !xFCMap
.is() || !xFCMap
->GetCharCount(), "vcl", "no charmap" );
804 // get unicode<->glyph encoding
805 // TODO? avoid sft mapping by using the xFCMap itself
806 int nCharCount
= xFCMap
->GetCharCount();
807 sal_uInt32 nChar
= xFCMap
->GetFirstChar();
808 for( ; --nCharCount
>= 0; nChar
= xFCMap
->GetNextChar( nChar
) )
810 if( nChar
> 0xFFFF ) // TODO: allow UTF-32 chars
813 sal_Ucs nUcsChar
= static_cast<sal_Ucs
>(nChar
);
814 sal_uInt32 nGlyph
= ::MapChar( pSftFont
, nUcsChar
);
817 rUnicodeEnc
[ nUcsChar
] = nGlyph
;
824 ::CloseTTFont( pSftFont
);
827 const void* AquaSalGraphics::GetEmbedFontData(const PhysicalFontFace
*, long* /*pDataLen*/)
832 void AquaSalGraphics::FreeEmbedFontData( const void* pData
, long /*nDataLen*/ )
834 // TODO: implementing this only makes sense when the implementation of
835 // AquaSalGraphics::GetEmbedFontData() returns non-NULL
837 SAL_WARN_IF( (pData
==nullptr), "vcl", "AquaSalGraphics::FreeEmbedFontData() is not implemented");
840 bool AquaSalGraphics::IsFlipped() const
849 void AquaSalGraphics::RefreshRect(float lX
, float lY
, float lWidth
, float lHeight
)
852 if( ! mbWindow
) // view only on Window graphics
857 // update a little more around the designated rectangle
858 // this helps with antialiased rendering
859 // Rounding down x and width can accumulate a rounding error of up to 2
860 // The decrementing of x, the rounding error and the antialiasing border
861 // require that the width and the height need to be increased by four
862 const tools::Rectangle
aVclRect(Point(static_cast<long int>(lX
-1),
863 static_cast<long int>(lY
-1) ),
864 Size( static_cast<long int>(lWidth
+4),
865 static_cast<long int>(lHeight
+4) ) );
866 mpFrame
->maInvalidRect
.Union( aVclRect
);
879 bool AquaSalGraphics::CheckContext()
881 if (mbForeignContext
)
883 SAL_INFO("vcl.ios", "CheckContext() this=" << this << ", mbForeignContext, return true");
887 SAL_INFO( "vcl.ios", "CheckContext() this=" << this << ", not foreign, return false");
891 CGContextRef
AquaSalGraphics::GetContext()
901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */