Simplify a bit
[LibreOffice.git] / vcl / quartz / salgdi.cxx
blobb54c6da5119ae1e9321e7cd3ff12df0f16f29c0d
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 <sal/log.hxx>
22 #include <config_folders.h>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <basegfx/polygon/b2dpolygon.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/range/b2drectangle.hxx>
29 #include <osl/file.hxx>
30 #include <osl/process.h>
31 #include <rtl/bootstrap.h>
32 #include <rtl/strbuf.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <tools/long.hxx>
35 #include <comphelper/lok.hxx>
37 #include <vcl/metric.hxx>
38 #include <vcl/fontcharmap.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/sysdata.hxx>
42 #include <quartz/ctfonts.hxx>
43 #include <fontsubset.hxx>
44 #include <impfont.hxx>
45 #include <impfontcharmap.hxx>
46 #include <impfontmetricdata.hxx>
47 #include <font/fontsubstitution.hxx>
48 #include <font/PhysicalFontCollection.hxx>
50 #ifdef MACOSX
51 #include <osx/salframe.h>
52 #endif
53 #include <quartz/utils.h>
54 #ifdef IOS
55 #include "saldatabasic.hxx"
56 #endif
57 #include <sallayout.hxx>
58 #include <sft.hxx>
60 #include <config_features.h>
61 #include <vcl/skia/SkiaHelper.hxx>
62 #if HAVE_FEATURE_SKIA
63 #include <skia/osx/gdiimpl.hxx>
64 #endif
66 using namespace vcl;
68 namespace {
70 class CoreTextGlyphFallbackSubstititution
71 : public vcl::font::GlyphFallbackFontSubstitution
73 public:
74 bool FindFontSubstitute(vcl::font::FontSelectPattern&, LogicalFontInstance* pLogicalFont, OUString&) const override;
77 bool FontHasCharacter(CTFontRef pFont, const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen)
79 CGGlyph glyphs[nLen];
80 return CTFontGetGlyphsForCharacters(pFont, reinterpret_cast<const UniChar*>(rString.getStr() + nIndex), glyphs, nLen);
85 bool CoreTextGlyphFallbackSubstititution::FindFontSubstitute(vcl::font::FontSelectPattern& rPattern, LogicalFontInstance* pLogicalFont,
86 OUString& rMissingChars) const
88 bool bFound = false;
89 CoreTextStyle* pStyle = static_cast<CoreTextStyle*>(pLogicalFont);
90 CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(pStyle->GetStyleDict(), kCTFontAttributeName));
91 CFStringRef pStr = CreateCFString(rMissingChars);
92 if (pStr)
94 CTFontRef pFallback = CTFontCreateForString(pFont, pStr, CFRangeMake(0, CFStringGetLength(pStr)));
95 if (pFallback)
97 bFound = true;
99 // tdf#148470 remove the resolved chars from rMissing to flag which ones are still missing
100 // for an attempt with another font
101 OUStringBuffer aStillMissingChars;
102 for (sal_Int32 nStrIndex = 0; nStrIndex < rMissingChars.getLength();)
104 sal_Int32 nOldStrIndex = nStrIndex;
105 rMissingChars.iterateCodePoints(&nStrIndex);
106 sal_Int32 nCharLength = nStrIndex - nOldStrIndex;
107 if (!FontHasCharacter(pFallback, rMissingChars, nOldStrIndex, nCharLength))
108 aStillMissingChars.append(rMissingChars.getStr() + nOldStrIndex, nCharLength);
110 rMissingChars = aStillMissingChars.toString();
112 CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFallback);
113 FontAttributes rAttr = DevFontFromCTFontDescriptor(pDesc, nullptr);
115 rPattern.maSearchName = rAttr.GetFamilyName();
117 rPattern.SetWeight(rAttr.GetWeight());
118 rPattern.SetItalic(rAttr.GetItalic());
119 rPattern.SetPitch(rAttr.GetPitch());
120 rPattern.SetWidthType(rAttr.GetWidthType());
122 CFRelease(pFallback);
123 CFRelease(pDesc);
125 CFRelease(pStr);
128 return bFound;
131 CoreTextFontFace::CoreTextFontFace( const FontAttributes& rDFA, sal_IntPtr nFontId )
132 : vcl::font::PhysicalFontFace( rDFA )
133 , mnFontId( nFontId )
134 , mbFontCapabilitiesRead( false )
138 CoreTextFontFace::~CoreTextFontFace()
142 sal_IntPtr CoreTextFontFace::GetFontId() const
144 return mnFontId;
147 FontCharMapRef CoreTextFontFace::GetFontCharMap() const
149 // return the cached charmap
150 if( mxCharMap.is() )
151 return mxCharMap;
153 // set the default charmap
154 FontCharMapRef pCharMap( new FontCharMap() );
155 mxCharMap = pCharMap;
157 // get the CMAP byte size
158 // allocate a buffer for the CMAP raw data
159 const int nBufSize = GetFontTable( "cmap", nullptr );
160 SAL_WARN_IF( (nBufSize <= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable1 failed!");
161 if( nBufSize <= 0 )
162 return mxCharMap;
164 // get the CMAP raw data
165 std::vector<unsigned char> aBuffer( nBufSize );
166 const int nRawLength = GetFontTable( "cmap", aBuffer.data() );
167 SAL_WARN_IF( (nRawLength <= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable2 failed!");
168 if( nRawLength <= 0 )
169 return mxCharMap;
171 SAL_WARN_IF( (nBufSize!=nRawLength), "vcl", "CoreTextFontFace::GetFontCharMap : ByteCount mismatch!");
173 // parse the CMAP
174 CmapResult aCmapResult;
175 if( ParseCMAP( aBuffer.data(), nRawLength, aCmapResult ) )
177 FontCharMapRef xDefFontCharMap( new FontCharMap(aCmapResult) );
178 // create the matching charmap
179 mxCharMap = xDefFontCharMap;
182 return mxCharMap;
185 bool CoreTextFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
187 // read this only once per font
188 if( mbFontCapabilitiesRead )
190 rFontCapabilities = maFontCapabilities;
191 return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange;
193 mbFontCapabilitiesRead = true;
195 int nBufSize = GetFontTable( "OS/2", nullptr );
196 if( nBufSize > 0 )
198 // allocate a buffer for the OS/2 raw data
199 std::vector<unsigned char> aBuffer( nBufSize );
200 // get the OS/2 raw data
201 const int nRawLength = GetFontTable( "OS/2", aBuffer.data() );
202 if( nRawLength > 0 )
204 const unsigned char* pOS2Table = aBuffer.data();
205 vcl::getTTCoverage( maFontCapabilities.oUnicodeRange,
206 maFontCapabilities.oCodePageRange,
207 pOS2Table, nRawLength);
210 rFontCapabilities = maFontCapabilities;
211 return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange;
214 AquaSalGraphics::AquaSalGraphics()
215 : mnRealDPIX( 0 )
216 , mnRealDPIY( 0 )
218 SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this );
220 #if HAVE_FEATURE_SKIA
221 if(SkiaHelper::isVCLSkiaEnabled())
222 mpBackend.reset(new AquaSkiaSalGraphicsImpl(*this, maShared));
223 #else
224 if(false)
226 #endif
227 else
228 mpBackend.reset(new AquaGraphicsBackend(maShared));
230 for (int i = 0; i < MAX_FALLBACK; ++i)
231 mpTextStyle[i] = nullptr;
233 if (comphelper::LibreOfficeKit::isActive())
234 initWidgetDrawBackends(true);
237 AquaSalGraphics::~AquaSalGraphics()
239 SAL_INFO( "vcl.quartz", "AquaSalGraphics::~AquaSalGraphics() this=" << this );
241 maShared.unsetClipPath();
243 ReleaseFonts();
245 maShared.mpXorEmulation.reset();
247 #ifdef IOS
248 if (maShared.mbForeignContext)
249 return;
250 #endif
251 if (maShared.maLayer.isSet())
253 CGLayerRelease(maShared.maLayer.get());
255 else if (maShared.maContextHolder.isSet()
256 #ifdef MACOSX
257 && maShared.mbWindow
258 #endif
261 // destroy backbuffer bitmap context that we created ourself
262 CGContextRelease(maShared.maContextHolder.get());
263 maShared.maContextHolder.set(nullptr);
267 SalGraphicsImpl* AquaSalGraphics::GetImpl() const
269 return mpBackend->GetImpl();
272 void AquaSalGraphics::SetTextColor( Color nColor )
274 maShared.maTextColor = nColor;
275 // SAL_ DEBUG(std::hex << nColor << std::dec << "={" << maShared.maTextColor.GetRed() << ", " << maShared.maTextColor.GetGreen() << ", " << maShared.maTextColor.GetBlue() << ", " << maShared.maTextColor.GetAlpha() << "}");
278 void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel)
280 if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel])
282 mpTextStyle[nFallbackLevel]->GetFontMetric(rxFontMetric);
286 static bool AddTempDevFont(const OUString& rFontFileURL)
288 OUString aUSystemPath;
289 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSystemPath ) );
290 OString aCFileName = OUStringToOString( aUSystemPath, RTL_TEXTENCODING_UTF8 );
292 CFStringRef rFontPath = CFStringCreateWithCString(nullptr, aCFileName.getStr(), kCFStringEncodingUTF8);
293 CFURLRef rFontURL = CFURLCreateWithFileSystemPath(nullptr, rFontPath, kCFURLPOSIXPathStyle, true);
295 CFErrorRef error;
296 bool success = CTFontManagerRegisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, &error);
297 if (!success)
299 CFRelease(error);
301 CFRelease(rFontPath);
302 CFRelease(rFontURL);
304 return success;
307 static void AddTempFontDir( const OUString &rFontDirUrl )
309 osl::Directory aFontDir( rFontDirUrl );
310 osl::FileBase::RC rcOSL = aFontDir.open();
311 if( rcOSL == osl::FileBase::E_None )
313 osl::DirectoryItem aDirItem;
315 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
317 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
318 rcOSL = aDirItem.getFileStatus( aFileStatus );
319 if ( rcOSL == osl::FileBase::E_None )
321 AddTempDevFont(aFileStatus.getFileURL());
327 static void AddLocalTempFontDirs()
329 static bool bFirst = true;
330 if( !bFirst )
331 return;
333 bFirst = false;
335 // add private font files
337 OUString aBrandStr( "$BRAND_BASE_DIR" );
338 rtl_bootstrap_expandMacros( &aBrandStr.pData );
340 // internal font resources, required for normal operation, like OpenSymbol
341 AddTempFontDir( aBrandStr + "/" LIBO_SHARE_RESOURCE_FOLDER "/common/fonts/" );
343 AddTempFontDir( aBrandStr + "/" LIBO_SHARE_FOLDER "/fonts/truetype/" );
346 void AquaSalGraphics::GetDevFontList(vcl::font::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(vcl::font::PhysicalFontCollection*,
379 const OUString& rFontFileURL, const OUString& /*rFontName*/)
381 return ::AddTempDevFont(rFontFileURL);
384 void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
386 mpBackend->drawTextLayout(rLayout);
389 void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout)
391 #ifdef IOS
392 if (!mrShared.checkContext())
394 SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout() without context");
395 return;
397 #endif
399 const CoreTextStyle& rStyle = *static_cast<const CoreTextStyle*>(&rLayout.GetFont());
400 const vcl::font::FontSelectPattern& rFontSelect = rStyle.GetFontSelectPattern();
401 if (rFontSelect.mnHeight == 0)
403 SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout(): rFontSelect.mnHeight is zero!?");
404 return;
407 CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName));
408 CGAffineTransform aRotMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation);
410 Point aPos;
411 const GlyphItem* pGlyph;
412 std::vector<CGGlyph> aGlyphIds;
413 std::vector<CGPoint> aGlyphPos;
414 std::vector<bool> aGlyphOrientation;
415 int nStart = 0;
416 while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
418 CGPoint aGCPos = CGPointMake(aPos.X(), -aPos.Y());
420 // Whether the glyph should be upright in vertical mode or not
421 bool bUprightGlyph = false;
423 if (rStyle.mfFontRotation)
425 if (pGlyph->IsVertical())
427 bUprightGlyph = true;
428 // Adjust the position of upright (vertical) glyphs.
429 aGCPos.y -= CTFontGetAscent(pFont) - CTFontGetDescent(pFont);
431 else
433 // Transform the position of rotated glyphs.
434 aGCPos = CGPointApplyAffineTransform(aGCPos, aRotMatrix);
438 aGlyphIds.push_back(pGlyph->glyphId());
439 aGlyphPos.push_back(aGCPos);
440 aGlyphOrientation.push_back(bUprightGlyph);
443 if (aGlyphIds.empty())
444 return;
446 assert(aGlyphIds.size() == aGlyphPos.size());
447 #if 0
448 std::cerr << "aGlyphIds:[";
449 for (unsigned i = 0; i < aGlyphIds.size(); i++)
451 if (i > 0)
452 std::cerr << ",";
453 std::cerr << aGlyphIds[i];
455 std::cerr << "]\n";
456 std::cerr << "aGlyphPos:[";
457 for (unsigned i = 0; i < aGlyphPos.size(); i++)
459 if (i > 0)
460 std::cerr << ",";
461 std::cerr << aGlyphPos[i];
463 std::cerr << "]\n";
464 #endif
466 mrShared.maContextHolder.saveState();
467 RGBAColor textColor( mrShared.maTextColor );
469 // The view is vertically flipped (no idea why), flip it back.
470 CGContextScaleCTM(mrShared.maContextHolder.get(), 1.0, -1.0);
471 CGContextSetShouldAntialias(mrShared.maContextHolder.get(), !mrShared.mbNonAntialiasedText);
472 CGContextSetFillColor(mrShared.maContextHolder.get(), textColor.AsArray());
474 if (rStyle.mbFauxBold)
477 float fSize = rFontSelect.mnHeight / 23.0f;
478 CGContextSetStrokeColor(mrShared.maContextHolder.get(), textColor.AsArray());
479 CGContextSetLineWidth(mrShared.maContextHolder.get(), fSize);
480 CGContextSetTextDrawingMode(mrShared.maContextHolder.get(), kCGTextFillStroke);
483 auto aIt = aGlyphOrientation.cbegin();
484 while (aIt != aGlyphOrientation.cend())
486 bool bUprightGlyph = *aIt;
487 // Find the boundary of the run of glyphs with the same rotation, to be
488 // drawn together.
489 auto aNext = std::find(aIt, aGlyphOrientation.cend(), !bUprightGlyph);
490 size_t nStartIndex = std::distance(aGlyphOrientation.cbegin(), aIt);
491 size_t nLen = std::distance(aIt, aNext);
493 mrShared.maContextHolder.saveState();
494 if (rStyle.mfFontRotation && !bUprightGlyph)
496 CGContextRotateCTM(mrShared.maContextHolder.get(), rStyle.mfFontRotation);
498 CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, mrShared.maContextHolder.get());
499 mrShared.maContextHolder.restoreState();
501 aIt = aNext;
504 mrShared.maContextHolder.restoreState();
507 void AquaSalGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel)
509 // release the text style
510 for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i)
512 if (!mpTextStyle[i])
513 break;
514 mpTextStyle[i].clear();
517 if (!pReqFont)
518 return;
520 // update the text style
521 mpTextStyle[nFallbackLevel] = static_cast<CoreTextStyle*>(pReqFont);
524 std::unique_ptr<GenericSalLayout> AquaSalGraphics::GetTextLayout(int nFallbackLevel)
526 assert(mpTextStyle[nFallbackLevel]);
527 if (!mpTextStyle[nFallbackLevel])
528 return nullptr;
529 return std::make_unique<GenericSalLayout>(*mpTextStyle[nFallbackLevel]);
532 FontCharMapRef AquaSalGraphics::GetFontCharMap() const
534 if (!mpTextStyle[0])
536 return FontCharMapRef( new FontCharMap() );
539 return static_cast<const CoreTextFontFace*>(mpTextStyle[0]->GetFontFace())->GetFontCharMap();
542 bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
544 if (!mpTextStyle[0])
545 return false;
547 return static_cast<const CoreTextFontFace*>(mpTextStyle[0]->GetFontFace())->GetFontCapabilities(rFontCapabilities);
550 // fake a SFNT font directory entry for a font table
551 // see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html#Directory
552 static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen,
553 const unsigned char* /*pData*/, unsigned char*& rpDest )
555 // write entry tag
556 rpDest[ 0] = aTag[0];
557 rpDest[ 1] = aTag[1];
558 rpDest[ 2] = aTag[2];
559 rpDest[ 3] = aTag[3];
560 // TODO: get entry checksum and write it
561 // not too important since the subsetter doesn't care currently
562 // for( pData+nOfs ... pData+nOfs+nLen )
563 // write entry offset
564 rpDest[ 8] = static_cast<char>(nOfs >> 24);
565 rpDest[ 9] = static_cast<char>(nOfs >> 16);
566 rpDest[10] = static_cast<char>(nOfs >> 8);
567 rpDest[11] = static_cast<char>(nOfs >> 0);
568 // write entry length
569 rpDest[12] = static_cast<char>(nLen >> 24);
570 rpDest[13] = static_cast<char>(nLen >> 16);
571 rpDest[14] = static_cast<char>(nLen >> 8);
572 rpDest[15] = static_cast<char>(nLen >> 0);
573 // advance to next entry
574 rpDest += 16;
577 // fake a TTF or CFF font as directly accessing font file is not possible
578 // when only the fontid is known. This approach also handles *.font fonts.
579 bool AquaSalGraphics::GetRawFontData( const vcl::font::PhysicalFontFace* pFontData,
580 std::vector<unsigned char>& rBuffer, bool* pJustCFF )
582 const CoreTextFontFace* pMacFont = static_cast<const CoreTextFontFace*>(pFontData);
584 // short circuit for CFF-only fonts
585 const int nCffSize = pMacFont->GetFontTable( "CFF ", nullptr);
586 if( pJustCFF != nullptr )
588 *pJustCFF = (nCffSize > 0);
589 if( *pJustCFF)
591 rBuffer.resize( nCffSize);
592 const int nCffRead = pMacFont->GetFontTable( "CFF ", rBuffer.data());
593 if( nCffRead != nCffSize)
595 return false;
597 return true;
601 // get font table availability and size in bytes
602 const int nHeadSize = pMacFont->GetFontTable( "head", nullptr);
603 if( nHeadSize <= 0)
604 return false;
606 const int nMaxpSize = pMacFont->GetFontTable( "maxp", nullptr);
607 if( nMaxpSize <= 0)
608 return false;
610 const int nCmapSize = pMacFont->GetFontTable( "cmap", nullptr);
611 if( nCmapSize <= 0)
612 return false;
614 const int nNameSize = pMacFont->GetFontTable( "name", nullptr);
615 if( nNameSize <= 0)
616 return false;
618 const int nHheaSize = pMacFont->GetFontTable( "hhea", nullptr);
619 if( nHheaSize <= 0)
620 return false;
622 const int nHmtxSize = pMacFont->GetFontTable( "hmtx", nullptr);
623 if( nHmtxSize <= 0)
624 return false;
626 // get the ttf-glyf outline tables
627 int nLocaSize = 0;
628 int nGlyfSize = 0;
629 if( nCffSize <= 0)
631 nLocaSize = pMacFont->GetFontTable( "loca", nullptr);
632 if( nLocaSize <= 0)
633 return false;
635 nGlyfSize = pMacFont->GetFontTable( "glyf", nullptr);
636 if( nGlyfSize <= 0)
637 return false;
640 int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0;
641 if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional
643 nPrepSize = pMacFont->GetFontTable( "prep", nullptr);
644 nCvtSize = pMacFont->GetFontTable( "cvt ", nullptr);
645 nFpgmSize = pMacFont->GetFontTable( "fpgm", nullptr);
648 // prepare a byte buffer for a fake font
649 int nTableCount = 7;
650 nTableCount += (nPrepSize>0?1:0) + (nCvtSize>0?1:0) + (nFpgmSize>0?1:0) + (nGlyfSize>0?1:0);
651 const ByteCount nFdirSize = 12 + 16*nTableCount;
652 ByteCount nTotalSize = nFdirSize;
653 nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize;
655 if( nGlyfSize )
657 nTotalSize += nLocaSize + nGlyfSize;
659 else
661 nTotalSize += nCffSize;
663 nTotalSize += nHheaSize + nHmtxSize;
664 nTotalSize += nPrepSize + nCvtSize + nFpgmSize;
665 rBuffer.resize( nTotalSize );
667 // fake a SFNT font directory header
668 if( nTableCount < 16 )
670 int nLog2 = 0;
671 while( (nTableCount >> nLog2) > 1 ) ++nLog2;
672 rBuffer[ 1] = 1; // Win-TTF style scaler
673 rBuffer[ 5] = nTableCount; // table count
674 rBuffer[ 7] = nLog2*16; // searchRange
675 rBuffer[ 9] = nLog2; // entrySelector
676 rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
679 // get font table raw data and update the fake directory entries
680 ByteCount nOfs = nFdirSize;
681 unsigned char* pFakeEntry = &rBuffer[12];
682 if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs]))
683 return false;
685 FakeDirEntry( "cmap", nOfs, nCmapSize, rBuffer.data(), pFakeEntry );
686 nOfs += nCmapSize;
687 if( nCvtSize )
689 if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
690 return false;
692 FakeDirEntry( "cvt ", nOfs, nCvtSize, rBuffer.data(), pFakeEntry );
693 nOfs += nCvtSize;
695 if( nFpgmSize )
697 if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
698 return false;
700 FakeDirEntry( "fpgm", nOfs, nFpgmSize, rBuffer.data(), pFakeEntry );
701 nOfs += nFpgmSize;
703 if( nCffSize )
705 if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
706 return false;
708 FakeDirEntry( "CFF ", nOfs, nCffSize, rBuffer.data(), pFakeEntry );
709 nOfs += nGlyfSize;
711 else
713 if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
714 return false;
716 FakeDirEntry( "glyf", nOfs, nGlyfSize, rBuffer.data(), pFakeEntry );
717 nOfs += nGlyfSize;
719 if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
720 return false;
722 FakeDirEntry( "loca", nOfs, nLocaSize, rBuffer.data(), pFakeEntry );
723 nOfs += nLocaSize;
725 if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
726 return false;
728 FakeDirEntry( "head", nOfs, nHeadSize, rBuffer.data(), pFakeEntry );
729 nOfs += nHeadSize;
731 if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
732 return false;
734 FakeDirEntry( "hhea", nOfs, nHheaSize, rBuffer.data(), pFakeEntry );
735 nOfs += nHheaSize;
736 if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
737 return false;
739 FakeDirEntry( "hmtx", nOfs, nHmtxSize, rBuffer.data(), pFakeEntry );
740 nOfs += nHmtxSize;
741 if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
742 return false;
744 FakeDirEntry( "maxp", nOfs, nMaxpSize, rBuffer.data(), pFakeEntry );
745 nOfs += nMaxpSize;
746 if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
747 return false;
749 FakeDirEntry( "name", nOfs, nNameSize, rBuffer.data(), pFakeEntry );
750 nOfs += nNameSize;
751 if( nPrepSize )
753 if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
754 return false;
756 FakeDirEntry( "prep", nOfs, nPrepSize, rBuffer.data(), pFakeEntry );
757 nOfs += nPrepSize;
760 SAL_WARN_IF( (nOfs!=nTotalSize), "vcl", "AquaSalGraphics::GetRawFontData (nOfs!=nTotalSize)");
762 return true;
765 void AquaSalGraphics::GetGlyphWidths( const vcl::font::PhysicalFontFace* pFontData, bool bVertical,
766 std::vector< sal_Int32 >& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
768 rGlyphWidths.clear();
769 rUnicodeEnc.clear();
771 std::vector<unsigned char> aBuffer;
772 if( !GetRawFontData( pFontData, aBuffer, nullptr ) )
773 return;
775 // TODO: modernize psprint's horrible fontsubset C-API
776 // this probably only makes sense after the switch to another SCM
777 // that can preserve change history after file renames
779 // use the font subsetter to get the widths
780 TrueTypeFont* pSftFont = nullptr;
781 SFErrCodes nRC = ::OpenTTFontBuffer(static_cast<void*>(aBuffer.data()), aBuffer.size(), 0, &pSftFont,
782 pFontData->GetFontCharMap());
783 if( nRC != SFErrCodes::Ok )
784 return;
786 SalGraphics::GetGlyphWidths(*pSftFont, *pFontData, bVertical, rGlyphWidths, rUnicodeEnc);
788 ::CloseTTFont( pSftFont );
791 const void* AquaSalGraphics::GetEmbedFontData(const vcl::font::PhysicalFontFace*, tools::Long* /*pDataLen*/)
793 return nullptr;
796 void AquaSalGraphics::FreeEmbedFontData( const void* pData, tools::Long /*nDataLen*/ )
798 // TODO: implementing this only makes sense when the implementation of
799 // AquaSalGraphics::GetEmbedFontData() returns non-NULL
800 SAL_WARN_IF( (pData==nullptr), "vcl", "AquaSalGraphics::FreeEmbedFontData() is not implemented");
803 void AquaSalGraphics::Flush()
805 mpBackend->Flush();
808 void AquaSalGraphics::Flush( const tools::Rectangle& rRect )
810 mpBackend->Flush( rRect );
813 #ifdef IOS
815 bool AquaSharedAttributes::checkContext()
817 if (mbForeignContext)
819 SAL_INFO("vcl.ios", "CheckContext() this=" << this << ", mbForeignContext, return true");
820 return true;
823 SAL_INFO( "vcl.ios", "CheckContext() this=" << this << ", not foreign, return false");
824 return false;
827 #endif
829 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */