Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / quartz / salgdi.cxx
blob45a4f245e17c6dcc2ca9642c91672a2a5cea987b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
45 #include "outdev.h"
46 #include "PhysicalFontCollection.hxx"
48 #ifdef MACOSX
49 #include "osx/salframe.h"
50 #endif
51 #include "quartz/utils.h"
52 #ifdef IOS
53 #include "saldatabasic.hxx"
54 #endif
55 #include "sallayout.hxx"
56 #include "sft.hxx"
58 using namespace vcl;
60 class CoreTextGlyphFallbackSubstititution
61 : public ImplGlyphFallbackFontSubstitution
63 public:
64 bool FindFontSubstitute(FontSelectPattern&, OUString&) const override;
67 bool CoreTextGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern& rPattern,
68 OUString& rMissingChars) const
70 bool bFound = false;
71 CoreTextStyle rStyle(rPattern);
72 CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName));
73 CFStringRef pStr = CreateCFString(rMissingChars);
74 if (pStr)
76 CTFontRef pFallback = CTFontCreateForString(pFont, pStr, CFRangeMake(0, CFStringGetLength(pStr)));
77 if (pFallback)
79 bFound = true;
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));
95 CFRelease(pFallback);
96 CFRelease(pDesc);
98 CFRelease(pStr);
101 return bFound;
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
131 if( mxCharMap.is() )
132 return mxCharMap;
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!");
142 if( nBufSize <= 0 )
143 return mxCharMap;
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 )
150 return mxCharMap;
152 SAL_WARN_IF( (nBufSize!=nRawLength), "vcl", "CoreTextFontFace::GetFontCharMap : ByteCount mismatch!");
154 // parse the CMAP
155 CmapResult aCmapResult;
156 if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
158 FontCharMapRef xDefFontCharMap( new FontCharMap(aCmapResult) );
159 // create the matching charmap
160 mxCharMap = xDefFontCharMap;
163 return mxCharMap;
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 );
177 if( nBufSize > 0 )
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] );
183 if( nRawLength > 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()
196 : mxLayer( nullptr )
197 , mrContext( nullptr )
198 #ifdef MACOSX
199 , mpFrame( nullptr )
200 #endif
201 #if OSL_DEBUG_LEVEL > 0
202 , mnContextStackDepth( 0 )
203 #endif
204 , mpXorEmulation( nullptr )
205 , mnXorMode( 0 )
206 , mnWidth( 0 )
207 , mnHeight( 0 )
208 , mnBitmapDepth( 0 )
209 , mnRealDPIX( 0 )
210 , mnRealDPIY( 0 )
211 , mxClipPath( nullptr )
212 , maLineColor( COL_WHITE )
213 , maFillColor( COL_BLACK )
214 , maTextColor( COL_BLACK )
215 , mbNonAntialiasedText( false )
216 , mbPrinter( false )
217 , mbVirDev( false )
218 #ifdef MACOSX
219 , mbWindow( false )
220 #else
221 , mbForeignContext( false )
222 #endif
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 );
237 if( mxClipPath )
239 SAL_INFO("vcl.cg", "CGPathRelease(" << mxClipPath << ")" );
240 CGPathRelease( mxClipPath );
243 for (int i = 0; i < MAX_FALLBACK; ++i)
244 delete mpTextStyle[i];
246 if( mpXorEmulation )
247 delete mpXorEmulation;
249 #ifdef IOS
250 if (mbForeignContext)
251 return;
252 #endif
253 if( mxLayer )
255 SAL_INFO("vcl.cg", "CGLayerRelease(" << mxLayer << ")" );
256 CGLayerRelease( mxLayer );
258 else if( mrContext
259 #ifdef MACOSX
260 && mbWindow
261 #endif
264 // destroy backbuffer bitmap context that we created ourself
265 SAL_INFO("vcl.cg", "CGContextRelease(" << mrContext << ")" );
266 CGContextRelease( mrContext );
267 mrContext = nullptr;
271 SalGraphicsImpl* AquaSalGraphics::GetImpl() const
273 return nullptr;
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);
299 CFErrorRef error;
300 bool success = CTFontManagerRegisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, &error);
301 if (!success)
303 CFRelease(error);
305 CFRelease(rFontPath);
306 CFRelease(rFontURL);
308 return success;
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;
334 if( !bFirst )
335 return;
337 bFirst = false;
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);
390 return bRC;
392 return false;
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);
401 return bRC;
403 return false;
406 void AquaSalGraphics::DrawTextLayout(const CommonSalLayout& rLayout)
408 const CoreTextStyle& rStyle = rLayout.getFontData();
409 const FontSelectPattern& rFontSelect = rStyle.maFontSelData;
410 if (rFontSelect.mnHeight == 0)
411 return;
413 CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName));
414 CGAffineTransform aRotMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation);
416 Point aPos;
417 const GlyphItem* pGlyph;
418 std::vector<CGGlyph> aGlyphIds;
419 std::vector<CGPoint> aGlyphPos;
420 std::vector<bool> aGlyphOrientation;
421 int nStart = 0;
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);
437 else
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())
450 return;
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
464 // drawn together.
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);
475 aIt = aNext;
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
491 if( !pReqFont )
493 mpFontData[nFallbackLevel] = nullptr;
494 return;
497 // update the text style
498 mpFontData[nFallbackLevel] = static_cast<const CoreTextFontFace*>(pReqFont->mpFontData);
499 mpTextStyle[nFallbackLevel] = new CoreTextStyle(*pReqFont);
501 SAL_INFO("vcl.ct",
502 "SetFont"
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]);
521 return nullptr;
524 const FontCharMapRef AquaSalGraphics::GetFontCharMap() const
526 if (!mpFontData[0])
528 FontCharMapRef xFontCharMap( new FontCharMap() );
529 return xFontCharMap;
532 return mpFontData[0]->GetFontCharMap();
535 bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
537 if (!mpFontData[0])
538 return false;
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 )
548 // write entry tag
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
567 rpDest += 16;
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);
582 if( *pJustCFF)
584 rBuffer.resize( nCffSize);
585 const int nCffRead = pMacFont->GetFontTable( "CFF ", &rBuffer[0]);
586 if( nCffRead != nCffSize)
588 return false;
590 return true;
594 // get font table availability and size in bytes
595 const int nHeadSize = pMacFont->GetFontTable( "head", nullptr);
596 if( nHeadSize <= 0)
597 return false;
599 const int nMaxpSize = pMacFont->GetFontTable( "maxp", nullptr);
600 if( nMaxpSize <= 0)
601 return false;
603 const int nCmapSize = pMacFont->GetFontTable( "cmap", nullptr);
604 if( nCmapSize <= 0)
605 return false;
607 const int nNameSize = pMacFont->GetFontTable( "name", nullptr);
608 if( nNameSize <= 0)
609 return false;
611 const int nHheaSize = pMacFont->GetFontTable( "hhea", nullptr);
612 if( nHheaSize <= 0)
613 return false;
615 const int nHmtxSize = pMacFont->GetFontTable( "hmtx", nullptr);
616 if( nHmtxSize <= 0)
617 return false;
619 // get the ttf-glyf outline tables
620 int nLocaSize = 0;
621 int nGlyfSize = 0;
622 if( nCffSize <= 0)
624 nLocaSize = pMacFont->GetFontTable( "loca", nullptr);
625 if( nLocaSize <= 0)
626 return false;
628 nGlyfSize = pMacFont->GetFontTable( "glyf", nullptr);
629 if( nGlyfSize <= 0)
630 return false;
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
642 int nTableCount = 7;
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;
648 if( nGlyfSize )
650 nTotalSize += nLocaSize + nGlyfSize;
652 else
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 )
663 int nLog2 = 0;
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]))
676 return false;
678 FakeDirEntry( "cmap", nOfs, nCmapSize, &rBuffer[0], pFakeEntry );
679 nOfs += nCmapSize;
680 if( nCvtSize )
682 if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
683 return false;
685 FakeDirEntry( "cvt ", nOfs, nCvtSize, &rBuffer[0], pFakeEntry );
686 nOfs += nCvtSize;
688 if( nFpgmSize )
690 if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
691 return false;
693 FakeDirEntry( "fpgm", nOfs, nFpgmSize, &rBuffer[0], pFakeEntry );
694 nOfs += nFpgmSize;
696 if( nCffSize )
698 if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
699 return false;
701 FakeDirEntry( "CFF ", nOfs, nCffSize, &rBuffer[0], pFakeEntry );
702 nOfs += nGlyfSize;
704 else
706 if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
707 return false;
709 FakeDirEntry( "glyf", nOfs, nGlyfSize, &rBuffer[0], pFakeEntry );
710 nOfs += nGlyfSize;
712 if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
713 return false;
715 FakeDirEntry( "loca", nOfs, nLocaSize, &rBuffer[0], pFakeEntry );
716 nOfs += nLocaSize;
718 if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
719 return false;
721 FakeDirEntry( "head", nOfs, nHeadSize, &rBuffer[0], pFakeEntry );
722 nOfs += nHeadSize;
724 if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
725 return false;
727 FakeDirEntry( "hhea", nOfs, nHheaSize, &rBuffer[0], pFakeEntry );
728 nOfs += nHheaSize;
729 if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
730 return false;
732 FakeDirEntry( "hmtx", nOfs, nHmtxSize, &rBuffer[0], pFakeEntry );
733 nOfs += nHmtxSize;
734 if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
735 return false;
737 FakeDirEntry( "maxp", nOfs, nMaxpSize, &rBuffer[0], pFakeEntry );
738 nOfs += nMaxpSize;
739 if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
740 return false;
742 FakeDirEntry( "name", nOfs, nNameSize, &rBuffer[0], pFakeEntry );
743 nOfs += nNameSize;
744 if( nPrepSize )
746 if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
747 return false;
749 FakeDirEntry( "prep", nOfs, nPrepSize, &rBuffer[0], pFakeEntry );
750 nOfs += nPrepSize;
753 SAL_WARN_IF( (nOfs!=nTotalSize), "vcl", "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
755 return true;
758 void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
759 std::vector< sal_Int32 >& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
761 rGlyphWidths.clear();
762 rUnicodeEnc.clear();
764 std::vector<unsigned char> aBuffer;
765 if( !GetRawFontData( pFontData, aBuffer, nullptr ) )
766 return;
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);
775 if( nRC != SF_OK )
776 return;
778 const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
779 if( nGlyphCount > 0 )
781 // get glyph metrics
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 );
791 if( pGlyphMetrics )
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
811 break;
813 sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
814 sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar );
815 if( nGlyph > 0 )
817 rUnicodeEnc[ nUcsChar ] = nGlyph;
821 xFCMap = nullptr;
824 ::CloseTTFont( pSftFont );
827 const void* AquaSalGraphics::GetEmbedFontData(const PhysicalFontFace*, long* /*pDataLen*/)
829 return nullptr;
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
836 (void)pData;
837 SAL_WARN_IF( (pData==nullptr), "vcl", "AquaSalGraphics::FreeEmbedFontData() is not implemented");
840 bool AquaSalGraphics::IsFlipped() const
842 #ifdef MACOSX
843 return mbWindow;
844 #else
845 return false;
846 #endif
849 void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight)
851 #ifdef MACOSX
852 if( ! mbWindow ) // view only on Window graphics
853 return;
855 if( mpFrame )
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 );
868 #else
869 (void) lX;
870 (void) lY;
871 (void) lWidth;
872 (void) lHeight;
873 return;
874 #endif
877 #ifdef IOS
879 bool AquaSalGraphics::CheckContext()
881 if (mbForeignContext)
883 SAL_INFO("vcl.ios", "CheckContext() this=" << this << ", mbForeignContext, return true");
884 return true;
887 SAL_INFO( "vcl.ios", "CheckContext() this=" << this << ", not foreign, return false");
888 return false;
891 CGContextRef AquaSalGraphics::GetContext()
893 if ( !mrContext )
894 CheckContext();
896 return mrContext;
899 #endif
901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */