summaryrefslogtreecommitdiff
path: root/vcl/coretext
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/coretext')
-rw-r--r--vcl/coretext/salcoretextfontutils.cxx629
-rw-r--r--vcl/coretext/salcoretextlayout.cxx485
-rw-r--r--vcl/coretext/salcoretextstyle.cxx121
-rw-r--r--vcl/coretext/salgdi.cxx267
4 files changed, 1502 insertions, 0 deletions
diff --git a/vcl/coretext/salcoretextfontutils.cxx b/vcl/coretext/salcoretextfontutils.cxx
new file mode 100644
index 000000000000..a9c0871e0157
--- /dev/null
+++ b/vcl/coretext/salcoretextfontutils.cxx
@@ -0,0 +1,629 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "coretext/common.h"
+
+#include "coretext/salcoretextfontutils.hxx"
+#include "coretext/salgdi.h"
+
+#include "sft.hxx"
+
+#ifdef MACOSX
+#include "aqua/salinst.h"
+#else // IOS
+#include "ios/salinst.h"
+#endif
+
+static bool GetDevFontAttributes( CTFontDescriptorRef font_descriptor, ImplDevFontAttributes& rDFA )
+{
+ int value = 0;
+
+ // reset the attributes
+ rDFA.SetFamilyType( FAMILY_DONTKNOW );
+ rDFA.SetPitch( PITCH_VARIABLE );
+ rDFA.SetWidthType( WIDTH_NORMAL );
+ rDFA.SetWeight( WEIGHT_NORMAL );
+ rDFA.SetItalic( ITALIC_NONE );
+ rDFA.SetSymbolFlag( false );
+ rDFA.mbOrientation = true;
+ rDFA.mbDevice = true;
+ rDFA.mnQuality = 0;
+
+#if defined(MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+ CTFontRef font = CTFontCreateWithFontDescriptor(font_descriptor, 0.0, NULL);
+ CFDataRef rHeadTable = CTFontCopyTable(font, kCTFontTableHead, kCTFontTableOptionNoOptions);
+ CFRelease(font);
+ if(!rHeadTable || CFDataGetLength(rHeadTable) == 0)
+ {
+ SafeCFRelease(rHeadTable);
+ return false;
+ }
+ CFRelease(rHeadTable);
+#else
+ CFNumberRef format = (CFNumberRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFormatAttribute);
+ CFNumberGetValue(format, kCFNumberIntType, &value);
+ CFRelease(format);
+
+ if(value == kCTFontFormatBitmap)
+ {
+ /* we don't want bitmap fonts */
+ return false;
+ }
+#endif
+ rDFA.mbSubsettable = true;
+ rDFA.mbEmbeddable = false;
+
+ CFStringRef family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFamilyNameAttribute);
+ rDFA.SetFamilyName( GetOUString(family_name) );
+ CFRelease(family_name);
+
+ CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontTraitsAttribute);
+ CFNumberRef symbolics = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait);
+ CFNumberGetValue(symbolics, kCFNumberIntType, &value);
+ CFRelease(symbolics);
+
+ if(value & kCTFontMonoSpaceTrait)
+ {
+ rDFA.SetPitch( PITCH_FIXED );
+ }
+
+ if(value & kCTFontItalicTrait)
+ {
+ rDFA.SetItalic( ITALIC_NORMAL );
+ }
+
+ if(value & kCTFontBoldTrait)
+ {
+ rDFA.SetWeight( WEIGHT_BOLD );
+ }
+
+ if(value & kCTFontCondensedTrait)
+ {
+ rDFA.SetWidthType( WIDTH_CONDENSED );
+ }
+ else if(value & kCTFontExpandedTrait)
+ {
+ rDFA.SetWidthType( WIDTH_EXPANDED );
+ }
+ switch(value & kCTFontClassMaskTrait)
+ {
+ case kCTFontOldStyleSerifsClass:
+ rDFA.SetFamilyType( FAMILY_ROMAN );
+ break;
+ case kCTFontTransitionalSerifsClass:
+ case kCTFontModernSerifsClass:
+ case kCTFontClarendonSerifsClass:
+ case kCTFontSlabSerifsClass:
+ case kCTFontFreeformSerifsClass:
+ break;
+ case kCTFontSansSerifClass:
+ rDFA.SetFamilyType( FAMILY_SWISS );
+ case kCTFontOrnamentalsClass:
+ rDFA.SetFamilyType( FAMILY_DECORATIVE );
+ break;
+ case kCTFontScriptsClass:
+ rDFA.SetFamilyType( FAMILY_SCRIPT );
+ break;
+ case kCTFontSymbolicClass:
+ rDFA.SetSymbolFlag( true );
+ break;
+ }
+
+ CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontWeightTrait);
+ float fdval = 0.0;
+ CFNumberGetValue(weight, kCFNumberFloatType, &fdval);
+ if(fdval > 0.6)
+ {
+ rDFA.SetWeight( WEIGHT_BLACK );
+ }
+ else if(fdval > 0.4)
+ {
+ rDFA.SetWeight( WEIGHT_ULTRABOLD );
+ }
+ else if (fdval > 0.3)
+ {
+ rDFA.SetWeight( WEIGHT_BOLD );
+ }
+ else if (fdval > 0.0)
+ {
+ rDFA.SetWeight( WEIGHT_SEMIBOLD );
+ }
+ else if (fdval <= -0.8)
+ {
+ rDFA.SetWeight( WEIGHT_ULTRALIGHT );
+ }
+ else if (fdval <= -0.4)
+ {
+ rDFA.SetWeight( WEIGHT_LIGHT );
+ }
+ else if (fdval <= -0.3)
+ {
+ rDFA.SetWeight( WEIGHT_SEMILIGHT );
+ }
+ else if (fdval <= -0.2)
+ {
+ rDFA.SetWeight( WEIGHT_THIN );
+ }
+ else
+ {
+ rDFA.SetWeight( WEIGHT_NORMAL );
+ }
+
+ CFStringRef string_ref = (CFStringRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontStyleNameAttribute);
+ rtl::OUString font_name = GetOUString(string_ref);
+ rtl::OUString font_name_lc(font_name.toAsciiLowerCase());
+ CFRelease(string_ref);
+
+ // heuristics to adjust font slant
+ if( (font_name_lc.indexOf("oblique") != -1) ||
+ (font_name_lc.indexOf("inclined") != -1) ||
+ (font_name_lc.indexOf("slanted") != -1) )
+ {
+ rDFA.SetItalic( ITALIC_OBLIQUE );
+ }
+
+ // heuristics to adjust font width
+ if (font_name_lc.indexOf("narrow") != -1)
+ {
+ rDFA.SetWidthType( WIDTH_SEMI_CONDENSED );
+ }
+
+ // heuristics for font family type
+ if( (font_name_lc.indexOf("script") != -1) ||
+ (font_name_lc.indexOf("chancery") != -1) ||
+ (font_name_lc.indexOf("zapfino") != -1))
+ {
+ rDFA.SetFamilyType( FAMILY_SCRIPT );
+ }
+ else if( (font_name_lc.indexOf("comic") != -1) ||
+ (font_name_lc.indexOf("outline") != -1) ||
+ (font_name_lc.indexOf("pinpoint") != -1) )
+ {
+ rDFA.SetFamilyType( FAMILY_DECORATIVE );
+ }
+ else if( (font_name_lc.indexOf("sans") != -1) ||
+ (font_name_lc.indexOf("arial") != -1) )
+ {
+ rDFA.SetFamilyType( FAMILY_SWISS );
+ }
+ else if( (font_name_lc.indexOf("roman") != -1) ||
+ (font_name_lc.indexOf("times") != -1) )
+ {
+ rDFA.SetFamilyType( FAMILY_ROMAN );
+ }
+ return true;
+}
+
+SystemFontList::SystemFontList()
+{
+ CTFontCollectionRef font_collection = CTFontCollectionCreateFromAvailableFonts(NULL);
+ if(font_collection)
+ {
+ CFArrayRef font_descriptors = CTFontCollectionCreateMatchingFontDescriptors(font_collection);
+
+ if(font_descriptors)
+ {
+ for(int i = 0; i < CFArrayGetCount(font_descriptors); i++)
+ {
+ CTFontDescriptorRef font_descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(font_descriptors, i);
+ CTFontRef font = CTFontCreateWithFontDescriptor(font_descriptor, 0, NULL);
+ if(font)
+ {
+ ImplDevFontAttributes devfont_attr;
+ if(GetDevFontAttributes( font_descriptor, devfont_attr ) )
+ {
+ CoreTextPhysicalFontFace* font_face = new CoreTextPhysicalFontFace(devfont_attr, font);
+ if(font_face && font_face->GetCTFont())
+ {
+ m_aFontContainer [ font_face->GetCTFont() ] = font_face;
+ }
+ }
+ CFRelease(font);
+ }
+ }
+ CFRelease(font_descriptors);
+ }
+ CFRelease(font_collection);
+ }
+
+}
+
+SystemFontList::~SystemFontList()
+{
+ CoreTextFontContainer::const_iterator it = m_aFontContainer.begin();
+ for(; it != m_aFontContainer.end(); ++it )
+ delete (*it).second;
+ m_aFontContainer.clear();
+}
+
+CoreTextPhysicalFontFace* SystemFontList::GetFontDataFromRef( CTFontRef font ) const
+{
+ CoreTextFontContainer::const_iterator it = m_aFontContainer.find( font );
+ return it == m_aFontContainer.end() ? NULL : (*it).second;
+}
+
+
+void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
+{
+ CoreTextFontContainer::const_iterator it = m_aFontContainer.begin();
+ for(; it != m_aFontContainer.end(); ++it )
+ {
+ rFontList.Add( (*it).second->Clone() );
+ }
+}
+
+CoreTextPhysicalFontFace::CoreTextPhysicalFontFace( const ImplDevFontAttributes& rDFA, CTFontRef font )
+: PhysicalFontFace( rDFA, 0 )
+, m_CTFontRef((CTFontRef)CFRetain(font))
+, m_pCharMap( NULL )
+, m_bHasOs2Table( false )
+, m_bOs2TableRead( false )
+, m_bCmapTableRead( false )
+, m_bHasCJKSupport( false )
+, m_bFontCapabilitiesRead( false )
+{
+ SAL_INFO( "vcl.coretext.font", "retain " << font << " as " << m_CTFontRef );
+}
+
+CoreTextPhysicalFontFace::~CoreTextPhysicalFontFace()
+{
+ if( m_pCharMap )
+ {
+ m_pCharMap->DeReference();
+ }
+ SAL_INFO( "vcl.coretext.font", "release " << m_CTFontRef );
+ SafeCFRelease(m_CTFontRef);
+}
+
+PhysicalFontFace* CoreTextPhysicalFontFace::Clone() const
+{
+ CoreTextPhysicalFontFace* pClone = new CoreTextPhysicalFontFace(*this);
+ if( m_pCharMap )
+ {
+ m_pCharMap->AddReference();
+ }
+ if( m_CTFontRef )
+ {
+ pClone->m_CTFontRef = (CTFontRef)CFRetain(m_CTFontRef);
+ SAL_INFO( "vcl.coretext.font", "clone " << m_CTFontRef << " into " << pClone->m_CTFontRef );
+ }
+ return pClone;
+}
+
+ImplFontEntry* CoreTextPhysicalFontFace::CreateFontInstance(FontSelectPattern& rFSD) const
+{
+ return new ImplFontEntry(rFSD);
+}
+
+const ImplFontCharMap* CoreTextPhysicalFontFace::GetImplFontCharMap()
+{
+ // return the cached charmap
+ if( m_pCharMap )
+ {
+ return m_pCharMap;
+ }
+ // set the default charmap
+ m_pCharMap = ImplFontCharMap::GetDefaultMap();
+ m_pCharMap->AddReference();
+
+ // get the CMAP byte size
+ CFDataRef rCmapTable = CTFontCopyTable( m_CTFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions);
+ if(!rCmapTable)
+ {
+ return m_pCharMap;
+ }
+ if(!m_bCmapTableRead)
+ {
+ m_bCmapTableRead = true;
+ DetermineCJKSupport_cmap(rCmapTable);
+ }
+ // parse the CMAP
+ CmapResult aCmapResult;
+ if(ParseCMAP( CFDataGetBytePtr(rCmapTable), CFDataGetLength(rCmapTable), aCmapResult ) )
+ {
+ m_pCharMap = new ImplFontCharMap( aCmapResult );
+ m_pCharMap->AddReference();
+ }
+ CFRelease(rCmapTable);
+ return m_pCharMap;
+}
+
+bool CoreTextPhysicalFontFace::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities)
+{
+ // read this only once per font
+ if( m_bFontCapabilitiesRead )
+ {
+ rFontCapabilities = m_aFontCapabilities;
+ return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+ }
+ m_bFontCapabilitiesRead = true;
+
+ // get the GSUB table raw data
+ CFDataRef rGSUBTable = CTFontCopyTable( m_CTFontRef, kCTFontTableGSUB, kCTFontTableOptionNoOptions);
+ if(rGSUBTable)
+ {
+
+ vcl::getTTScripts(m_aFontCapabilities.maGSUBScriptTags,
+ CFDataGetBytePtr(rGSUBTable), CFDataGetLength(rGSUBTable));
+ CFRelease(rGSUBTable);
+ }
+ CFDataRef OS2_Table = CTFontCopyTable( m_CTFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions);
+ if(OS2_Table)
+ {
+ vcl::getTTCoverage(
+ m_aFontCapabilities.maUnicodeRange,
+ m_aFontCapabilities.maCodePageRange,
+ CFDataGetBytePtr(OS2_Table), CFDataGetLength(OS2_Table));
+ /* while we are at it let's solve HasCJK for the same price */
+ if(!m_bOs2TableRead )
+ {
+ m_bOs2TableRead = true;
+ m_bHasOs2Table = true;
+ DetermineCJKSupport_OS2(OS2_Table);
+ }
+ CFRelease(OS2_Table);
+ }
+ rFontCapabilities = m_aFontCapabilities;
+ return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+}
+
+struct font_table
+{
+ unsigned char* table;
+ unsigned char* dir_entry;
+ unsigned char* cursor;
+};
+
+void addTable(struct font_table* table, CTFontTableTag tag, CFDataRef data)
+{
+ if(data && CFDataGetLength(data) > 0)
+ {
+ *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig(tag);
+ table->dir_entry += 4;
+ *(uint32_t*)table->dir_entry = 0; /* TODO: checksum */
+ table->dir_entry += 4;
+ *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig((uint32_t)((uintptr_t)table->cursor - (uintptr_t)table));
+ table->dir_entry += 4;
+ *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig(CFDataGetLength(data));
+ table->dir_entry += 4;
+
+ memcpy(table->cursor, CFDataGetBytePtr(data), CFDataGetLength(data));
+ table->cursor += CFDataGetLength(data);
+ }
+}
+
+bool CoreTextPhysicalFontFace::GetRawFontData( std::vector<unsigned char>& rBuffer, bool* pJustCFF ) const
+{
+ bool rc;
+ int table_count = 0;
+
+ CFDataRef CFF_table = CTFontCopyTable( m_CTFontRef, kCTFontTableCFF, kCTFontTableOptionNoOptions);
+ if(pJustCFF)
+ {
+ if(CFF_table)
+ {
+ *pJustCFF = CFDataGetLength(CFF_table) ? true : false;
+ CFRelease(CFF_table);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ size_t total_len = 0;
+ CFDataRef head_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHead, kCTFontTableOptionNoOptions);
+ CFDataRef maxp_table = CTFontCopyTable( m_CTFontRef, kCTFontTableMaxp, kCTFontTableOptionNoOptions);
+ CFDataRef cmap_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHead, kCTFontTableOptionNoOptions);
+ CFDataRef name_table = CTFontCopyTable( m_CTFontRef, kCTFontTableName, kCTFontTableOptionNoOptions);
+ CFDataRef hhea_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHhea, kCTFontTableOptionNoOptions);
+ CFDataRef hmtx_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHmtx, kCTFontTableOptionNoOptions);
+ rc = false;
+ if(head_table && maxp_table && cmap_table && name_table && hhea_table && hmtx_table)
+ {
+ if(CFDataGetLength(head_table) &&
+ CFDataGetLength(maxp_table) &&
+ CFDataGetLength(name_table) &&
+ CFDataGetLength(hhea_table) &&
+ CFDataGetLength(hmtx_table))
+ {
+ table_count += 6;
+ total_len = CFDataGetLength(head_table) +
+ CFDataGetLength(maxp_table) +
+ CFDataGetLength(name_table) +
+ CFDataGetLength(hhea_table) +
+ CFDataGetLength(hmtx_table);
+ rc = true;
+ }
+ }
+
+ CFDataRef loca_table = NULL;
+ CFDataRef glyf_table = NULL;
+ CFDataRef prep_table = NULL;
+ CFDataRef cvt_table = NULL;
+ CFDataRef fpgm_table = NULL;
+ if(rc)
+ {
+ if(!CFF_table || CFDataGetLength(CFF_table) == 0)
+ {
+ loca_table = CTFontCopyTable( m_CTFontRef, kCTFontTableLoca, kCTFontTableOptionNoOptions);
+ glyf_table = CTFontCopyTable( m_CTFontRef, kCTFontTableGlyf, kCTFontTableOptionNoOptions);
+ if(!loca_table || !glyf_table || !CFDataGetLength(loca_table) || !CFDataGetLength(glyf_table))
+ {
+ rc = false;
+ }
+ else
+ {
+ table_count += 2;
+ total_len += CFDataGetLength(loca_table) + CFDataGetLength(glyf_table);
+ prep_table = CTFontCopyTable( m_CTFontRef, kCTFontTablePrep, kCTFontTableOptionNoOptions);
+ cvt_table = CTFontCopyTable( m_CTFontRef, kCTFontTableCvt, kCTFontTableOptionNoOptions);
+ fpgm_table = CTFontCopyTable( m_CTFontRef, kCTFontTableFpgm, kCTFontTableOptionNoOptions);
+ if(prep_table || CFDataGetLength(prep_table) > 0)
+ {
+ table_count += 1;
+ total_len += CFDataGetLength(prep_table);
+ }
+ if(cvt_table || CFDataGetLength(cvt_table) > 0)
+ {
+ table_count += 1;
+ total_len += CFDataGetLength(cvt_table);
+ }
+ if(fpgm_table || CFDataGetLength(fpgm_table) > 0)
+ {
+ table_count += 1;
+ total_len += CFDataGetLength(fpgm_table);
+ }
+ }
+ }
+ else
+ {
+ table_count += 1;
+ total_len += CFDataGetLength(CFF_table);
+ }
+ }
+ if(rc)
+ {
+ total_len += 12 + 16 * table_count;
+ rBuffer.resize(total_len);
+ struct font_table table;
+ unsigned char* cursor = &rBuffer[0];
+ int nLog2 = 0;
+
+ while( (table_count >> nLog2) > 1 ) ++nLog2;
+
+ table.table = cursor;
+ *(uint16_t*)cursor = CFSwapInt16HostToBig(1);
+ cursor += 2;
+ *(uint16_t*)cursor = 0;
+ cursor += 2;
+ *(uint16_t*)cursor = CFSwapInt16HostToBig(table_count);
+ cursor += 2;
+ *(uint16_t*)cursor = CFSwapInt16HostToBig(nLog2 * 16);
+ cursor += 2;
+ *(uint16_t*)cursor = CFSwapInt16HostToBig(nLog2);
+ cursor += 2;
+ *(uint16_t*)cursor = CFSwapInt16HostToBig((table_count - nLog2) * 16); // rangeShift
+ cursor += 2;
+ table.dir_entry = cursor;
+ cursor += (16 * table_count);
+ table.cursor = cursor;
+ addTable(&table, kCTFontTableCmap, cmap_table);
+ addTable(&table, kCTFontTableCvt, cvt_table);
+ addTable(&table, kCTFontTableFpgm, fpgm_table);
+ addTable(&table, kCTFontTableCFF, CFF_table);
+ addTable(&table, kCTFontTableGlyf, glyf_table);
+ addTable(&table, kCTFontTableLoca, loca_table);
+ addTable(&table, kCTFontTableHead, head_table);
+ addTable(&table, kCTFontTableHhea, hhea_table);
+ addTable(&table, kCTFontTableHmtx, hmtx_table);
+ addTable(&table, kCTFontTableMaxp, maxp_table);
+ addTable(&table, kCTFontTableName, name_table);
+ addTable(&table, kCTFontTablePrep, prep_table);
+ }
+ SafeCFRelease(cmap_table);
+ SafeCFRelease(cvt_table);
+ SafeCFRelease(fpgm_table);
+ SafeCFRelease(CFF_table);
+ SafeCFRelease(glyf_table);
+ SafeCFRelease(loca_table);
+ SafeCFRelease(head_table);
+ SafeCFRelease(hhea_table);
+ SafeCFRelease(hmtx_table);
+ SafeCFRelease(maxp_table);
+ SafeCFRelease(name_table);
+ SafeCFRelease(prep_table);
+
+ return rc;
+}
+
+void CoreTextPhysicalFontFace::DetermineCJKSupport_OS2(CFDataRef rOS2Table)
+{
+ if(CFDataGetLength(rOS2Table) >= 48)
+ {
+ const unsigned short* pOS2buffer = (const unsigned short*)CFDataGetBytePtr(rOS2Table);
+ const unsigned short version = CFSwapInt16BigToHost(pOS2buffer[0]);
+ if( version >= 1)
+ {
+ const unsigned short unicode_range = CFSwapInt16BigToHost(pOS2buffer[23]);
+ if( unicode_range & 0x2DF0)
+ {
+ m_bHasCJKSupport = true;
+ }
+ }
+ }
+}
+
+void CoreTextPhysicalFontFace::DetermineCJKSupport_cmap(CFDataRef rCmapTable)
+{
+ int table_len = CFDataGetLength(rCmapTable) / 2;
+ if(table_len >= 12)
+ {
+ const unsigned short* pCmap = (const unsigned short*)CFDataGetBytePtr(rCmapTable);
+ if(pCmap[0] == 0)
+ {
+ short nb_sub_tables = CFSwapInt16BigToHost(pCmap[1]);
+ for(int i = 2; --nb_sub_tables >= 0 && i < table_len; i += 4)
+ {
+ short platform = CFSwapInt16BigToHost(pCmap[i]);
+ if( platform == kFontMacintoshPlatform )
+ {
+ short encoding = CFSwapInt16BigToHost(pCmap[i+1]);
+ if( encoding == kFontJapaneseScript ||
+ encoding == kFontTraditionalChineseScript ||
+ encoding == kFontKoreanScript ||
+ encoding == kFontSimpleChineseScript )
+ {
+ m_bHasCJKSupport = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool CoreTextPhysicalFontFace::HasCJKSupport( void )
+{
+ // read this only once per font
+ if(!m_bOs2TableRead )
+ {
+ m_bOs2TableRead = true;
+ CFDataRef rOS2Table = CTFontCopyTable( m_CTFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions);
+ if(rOS2Table)
+ {
+ m_bHasOs2Table = true;
+ DetermineCJKSupport_OS2(rOS2Table);
+ CFRelease(rOS2Table);
+ }
+ }
+ if( !m_bCmapTableRead && !m_bHasOs2Table && !m_bHasCJKSupport )
+ {
+ m_bCmapTableRead = true;
+ CFDataRef rCmapTable = CTFontCopyTable( m_CTFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions);
+ if(rCmapTable)
+ {
+ DetermineCJKSupport_cmap(rCmapTable);
+ CFRelease(rCmapTable);
+ }
+ }
+ return m_bHasCJKSupport;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/coretext/salcoretextlayout.cxx b/vcl/coretext/salcoretextlayout.cxx
new file mode 100644
index 000000000000..f57d6c8814c0
--- /dev/null
+++ b/vcl/coretext/salcoretextlayout.cxx
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "coretext/common.h"
+#include "coretext/salcoretextstyle.hxx"
+#include "coretext/salcoretextlayout.hxx"
+#include "coretext/salgdi.h"
+
+CoreTextLayout::CoreTextLayout(QuartzSalGraphics* graphics, CoreTextStyleInfo* style) :
+ m_graphics(graphics),
+ m_style(style),
+ m_glyphs_count(-1),
+ m_chars_count(-1),
+ m_chars2glyphs(NULL),
+ m_glyphs2chars(NULL),
+ m_glyphs(NULL),
+ m_char_widths(NULL),
+ m_glyph_advances(NULL),
+ m_glyph_positions(NULL),
+ m_typesetter(NULL),
+ m_line(NULL),
+ m_has_bound_rec(false),
+ m_base_advance(0),
+ m_cached_width(0.0F),
+ m_current_run_index(0),
+ m_current_glyph_index(0),
+ m_current_glyphrun_index(0),
+ m_runs(NULL)
+{
+}
+
+CoreTextLayout::~CoreTextLayout()
+{
+ Clean();
+}
+
+void CoreTextLayout::AdjustLayout( ImplLayoutArgs& /*rArgs*/ )
+{
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+ /* TODO */
+}
+
+void CoreTextLayout::Clean()
+{
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+ if(m_glyphs)
+ {
+ delete[] m_glyphs;
+ m_glyphs = NULL;
+ }
+ if(m_chars2glyphs)
+ {
+ delete[] m_chars2glyphs;
+ m_chars2glyphs = NULL;
+ }
+ if(m_glyphs2chars)
+ {
+ delete[] m_glyphs2chars;
+ m_glyphs2chars = NULL;
+ }
+ if(m_char_widths)
+ {
+ delete[] m_char_widths;
+ m_char_widths = NULL;
+ }
+ if(m_glyph_advances)
+ {
+ delete[] m_glyph_advances;
+ m_glyph_advances = NULL;
+ }
+ if(m_glyph_positions)
+ {
+ delete[] m_glyph_positions;
+ m_glyph_positions = NULL;
+ }
+ SafeCFRelease(m_typesetter);
+ SafeCFRelease(m_line);
+ m_has_bound_rec = false;
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+}
+
+void CoreTextLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+ QuartzSalGraphics& gr = static_cast<QuartzSalGraphics&>(rGraphics);
+ if(m_chars_count <= 0 || !gr.CheckContext())
+ {
+ return;
+ }
+ CGContextSaveGState( gr.mrContext );
+ Point pos = GetDrawPosition(Point(0,0));
+#if 0
+ SAL_INFO( "vcl.coretext.layout", "at pos (" << pos.X() << "," << pos.Y() << ")" );
+ CGContextSetTextMatrix(gr.mrContext, CGAffineTransformMakeScale(1.0, -1.0));
+ CGContextSetShouldAntialias( gr.mrContext, !gr.mbNonAntialiasedText );
+ CGContextSetTextPosition(gr.mrContext, pos.X(), pos.Y());
+ CTLineDraw(m_line, gr.mrContext);
+#else
+ InitGIA();
+ SAL_INFO( "vcl.coretext.layout", "at pos (" << pos.X() << "," << pos.Y() <<") ctfont=" << m_style->GetFont() );
+ CGFontRef cg_font = CTFontCopyGraphicsFont(m_style->GetFont(), NULL);
+ if(!cg_font)
+ {
+ SAL_INFO( "vcl.coretext.layout", "Error cg_font is NULL" );
+ return;
+ }
+ CGContextSetFont(gr.mrContext, cg_font);
+ CGContextSetFontSize(gr.mrContext, CTFontGetSize(m_style->GetFont()));
+ CGContextSetTextDrawingMode(gr.mrContext, kCGTextFill);
+ CGContextSetShouldAntialias( gr.mrContext, true );
+ if(m_style->GetColor())
+ {
+ CGContextSetFillColorWithColor(gr.mrContext, m_style->GetColor());
+ CGContextSetStrokeColorWithColor(gr.mrContext, m_style->GetColor());
+ }
+ else
+ {
+ CGContextSetRGBFillColor(gr.mrContext, 0.0, 0.0, 0.0, 1.0);
+ }
+ CFRelease(cg_font);
+ CGContextSetTextMatrix(gr.mrContext, CGAffineTransformMakeScale(1.0, -1.0));
+ CGContextSetShouldAntialias( gr.mrContext, !gr.mbNonAntialiasedText );
+ CGContextTranslateCTM(gr.mrContext, pos.X(), pos.Y());
+ CGContextShowGlyphs(gr.mrContext, m_glyphs, m_glyphs_count);
+#endif
+ // restore the original graphic context transformations
+ CGContextRestoreGState( gr.mrContext );
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+
+}
+
+// not needed. CoreText manage fallback directly
+void CoreTextLayout::DropGlyph( int /*nStart*/ ) {}
+
+long CoreTextLayout::FillDXArray( sal_Int32* pDXArray ) const
+{
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+ // short circuit requests which don't need full details
+ if( !pDXArray )
+ {
+ return GetTextWidth();
+ }
+
+ // initialize details about the resulting layout
+ InitGIA();
+
+ // distribute the widths among the string elements
+ long width = 0;
+ float scale = m_style->GetFontStretchFactor();
+ m_cached_width = 0;
+
+ for( int i = 0; i < m_chars_count; ++i )
+ {
+ // convert and adjust for accumulated rounding errors
+ m_cached_width += m_char_widths[i];
+ const long old_width = width;
+ width = round_to_long(m_cached_width * scale);
+ pDXArray[i] = width - old_width;
+ }
+ SAL_INFO( "vcl.coretext.layout", " width=" << width << " <--" );
+ return width;
+}
+
+bool CoreTextLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rVCLRect ) const
+{
+
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+ if ( !m_has_bound_rec )
+ {
+ QuartzSalGraphics& gr = static_cast<QuartzSalGraphics&>(rGraphics);
+ CGRect bound_rect = CTLineGetImageBounds( m_line, gr.mrContext );
+ if ( !CGRectIsNull( bound_rect ) )
+ {
+ m_bound_rect = Rectangle(
+ Point( round_to_long(bound_rect.origin.x * m_style->GetFontStretchFactor()),
+ round_to_long(bound_rect.origin.y - bound_rect.size.height )),
+ Size( round_to_long(bound_rect.size.width * m_style->GetFontStretchFactor()), round_to_long(bound_rect.size.height)));
+ m_bound_rect.Justify();
+ }
+ m_has_bound_rec = true;
+ }
+ rVCLRect = m_bound_rect;
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+ return true;
+}
+
+void CoreTextLayout::GetCaretPositions( int max_index, sal_Int32* caret_position) const
+{
+ SAL_INFO( "vcl.coretext.layout", "max_index " << max_index << " -->" );
+ int local_max = max_index < m_chars_count * 2 ? max_index : m_chars_count;
+ for(int i = 0 ; i < max_index - 1; i+=2)
+ {
+ CGFloat primary, secondary;
+ primary = CTLineGetOffsetForStringIndex(m_line, i >> 1, &secondary);
+ caret_position[i] = round_to_long(m_base_advance + primary);
+ caret_position[i+1] = round_to_long(m_base_advance + secondary);
+ i += 2;
+ }
+ for(int i = local_max ; i < max_index ; ++i)
+ {
+ caret_position[i] = -1;
+ }
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+}
+
+bool CoreTextLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const { return false; }
+
+int CoreTextLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
+{
+ SAL_INFO( "vcl.coretext.layout", "nLen=" << nLen << " nStart=" << nStart << " -->");
+ // get glyph measurements
+ InitGIA();
+
+ if( nStart < 0 ) // first glyph requested?
+ {
+ nStart = 0;
+ m_current_run_index = 0;
+ m_current_glyph_index = 0;
+ m_current_glyphrun_index = 0;
+ }
+ else if(nStart >= m_glyphs_count)
+ {
+ m_current_run_index = 0;
+ m_current_glyph_index = 0;
+ m_current_glyphrun_index = 0;
+ return 0;
+ }
+ if(!m_runs)
+ {
+ m_runs = CTLineGetGlyphRuns(m_line);
+ }
+ CFIndex nb_runs = CFArrayGetCount( m_runs );
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex( m_runs, m_current_run_index );
+ CFIndex nb_glyphs = CTRunGetGlyphCount( run );
+
+ int i = 0;
+ bool first = true;
+ while(i < nLen)
+ {
+ if(m_current_glyphrun_index >= nb_glyphs)
+ {
+ m_current_run_index += 1;
+ if(m_current_run_index >= nb_runs)
+ {
+ break;
+ }
+ run = (CTRunRef)CFArrayGetValueAtIndex( m_runs, m_current_run_index );
+ nb_glyphs = CTRunGetGlyphCount( run );
+ m_current_glyphrun_index = 0;
+ }
+ if(first)
+ {
+ CGPoint first_pos;
+ CTRunGetPositions(run, CFRangeMake(m_current_glyphrun_index,1), &first_pos);
+ Point pos(first_pos.x, first_pos.y);
+ rPos = GetDrawPosition(pos);
+ SAL_INFO( "vcl.coretext.layout", "rPos(" << rPos.X() << "," << rPos.Y() << ")" );
+ first = false;
+ }
+ pGlyphIDs[i] = m_glyphs[m_current_glyph_index];
+ if(pGlyphAdvances)
+ {
+ pGlyphAdvances[i] = m_glyph_advances[m_current_glyph_index];
+ }
+ if(pCharIndexes)
+ {
+ pCharIndexes[i] = m_glyphs2chars[m_current_glyph_index];
+ }
+ m_current_glyph_index += 1;
+ m_current_glyphrun_index += 1;
+ i += 1;
+ nStart += 1;
+ }
+ SAL_INFO( "vcl.coretext.layout", "i=" << i << " <--" );
+ return i;
+}
+
+int CoreTextLayout::GetTextBreak( long /*nMaxWidth*/, long /*nCharExtra*/, int /*nFactor*/ ) const
+{
+ /* TODO */
+ return false;
+}
+
+long CoreTextLayout::GetTextWidth() const
+{
+ SAL_INFO( "vcl.coretext.layout", "-->" );
+
+ CGRect bound_rect = CTLineGetImageBounds(m_line, m_graphics->GetContext());
+ long w = round_to_long(bound_rect.size.width * m_style->GetFontStretchFactor());
+ SAL_INFO( "vcl.coretext.layout", "w=" << w << " <--" );
+ return w;
+}
+
+// not needed. CoreText manage fallback directly
+void CoreTextLayout::InitFont() const
+{
+ SAL_INFO( "vcl.coretext.layout", "<-->" );
+}
+
+bool CoreTextLayout::InitGIA() const
+{
+ SAL_INFO( "vcl.coretext.layout", "count=" << m_chars_count << "-->" );
+
+ if( m_chars_count <= 0)
+ {
+ return false;
+ }
+ if(m_glyphs)
+ {
+ return true;
+ }
+
+ m_glyphs = new CGGlyph[m_glyphs_count];
+ m_char_widths = new int[ m_chars_count ];
+ m_chars2glyphs = new int[ m_chars_count ];
+ for( int i = 0; i < m_chars_count; ++i)
+ {
+ m_char_widths[i] = 0.0;
+ m_chars2glyphs[i] = -1;
+ }
+ m_glyphs2chars = new int[m_glyphs_count];
+ m_glyph_advances = new int[m_glyphs_count];
+ m_glyph_positions = new CGPoint[m_glyphs_count];
+
+
+ CFArrayRef runs = CTLineGetGlyphRuns( m_line );
+ CFIndex nb_runs = CFArrayGetCount( runs );
+ int p = 0;
+ for( CFIndex i = 0; i < nb_runs; ++i )
+ {
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex( runs, i );
+ if( run )
+ {
+ CFIndex nb_glyphs = CTRunGetGlyphCount( run );
+ if(nb_glyphs)
+ {
+ CFRange text_range = CTRunGetStringRange( run );
+ if( text_range.location != kCFNotFound && text_range.length > 0 )
+ {
+ CFIndex indices[ nb_glyphs ];
+ CGGlyph glyphs[ nb_glyphs ];
+ CTRunGetStringIndices( run, CFRangeMake( 0, 0 ), indices );
+ CTRunGetGlyphs( run, CFRangeMake( 0, 0 ), glyphs );
+ CTRunGetPositions( run, CFRangeMake( 0, 0 ), &m_glyph_positions[p] );
+ bool is_vertical_run = false;
+ CFDictionaryRef aDict = CTRunGetAttributes( run );
+ if ( aDict )
+ {
+ const CFBooleanRef aValue = (const CFBooleanRef)CFDictionaryGetValue( aDict, kCTVerticalFormsAttributeName );
+ is_vertical_run = (aValue == kCFBooleanTrue) ? true : false;
+ }
+
+ for (CFIndex j = 0 ; j < nb_glyphs; ++p, ++j )
+ {
+ m_glyphs[ p ] = glyphs[ j ];
+ SAL_INFO( "vcl.coretext.layout", "m_glyphys[" << p << "]=glyphs[" << j << "] run " << i << " : 0x" << std::hex << glyphs[j] << std::dec );
+ CFIndex k = indices[ j ];
+ m_glyphs2chars[p] = k;
+ m_chars2glyphs[k] = p;
+
+ if ( j < nb_glyphs - 1 )
+ {
+ m_char_widths[ k ] += m_glyph_positions[ p + 1 ].x - m_glyph_positions[ p ].x;
+ }
+ if( p > 0)
+ {
+ m_glyph_advances[p - 1] = m_glyph_positions[ p ].x - m_glyph_positions[p - 1].x;
+ }
+ }
+ }
+ }
+ }
+ }
+ SAL_INFO( "vcl.coretext.layout", "<--" );
+ return true;
+}
+
+bool CoreTextLayout::LayoutText(ImplLayoutArgs& args)
+{
+ SAL_INFO( "vcl.coretext.layout", "m_style=" << m_style << " font=" << m_style->GetFont() << " -->" );
+ Clean();
+ m_style->SetColor();
+ /* retreive MinCharPos EndCharPos Flags and Orientation */
+ SalLayout::AdjustLayout(args);
+ m_chars_count = mnEndCharPos - mnMinCharPos;
+
+ /* don't layout emptty (or worse negative size) strings */
+ if(m_chars_count <= 0)
+ {
+ return false;
+ }
+
+#ifdef IOS
+ // This might be caused by some red herring and be unnecessary
+ // once the CoreText code actually works;)
+
+ // If the string contains U+FFFD ("REPLACEMENT CHARACTER"), which
+ // happens at least for the ooo80484-1.slk document in
+ // sc_filters_test, the CTTypesetterCreateWithAttributedString()
+ // call below crashes, at least in the iOS simulator. Go figure.
+ // (In that case the string consists of *only* such characters,
+ // but play it safe.)
+ for (int i = 0; i < m_chars_count; i++)
+ {
+ if (args.mpStr[args.mnMinCharPos+i] == 0xFFFD)
+ return false;
+ }
+#endif
+
+ /* c0 and c1 are construction objects */
+ CFStringRef c0 = CFStringCreateWithCharactersNoCopy( NULL, &(args.mpStr[args.mnMinCharPos]), m_chars_count, kCFAllocatorNull );
+ if ( !c0 )
+ {
+ Clean();
+ return false;
+ }
+
+ CFStringRef keys[6];
+ CFTypeRef values[6];
+ int nb_attributes = 0;
+
+ keys[nb_attributes]= kCTFontAttributeName;
+ values[nb_attributes] = m_style->GetFont();
+ nb_attributes += 1;
+
+ CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void**)&keys,
+ (const void**)&values,
+ nb_attributes,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+
+ CFAttributedStringRef string = CFAttributedStringCreate( NULL, c0, attributes );
+ CFRelease( c0 );
+ CFRelease( attributes );
+ if ( !string )
+ {
+ Clean();
+ return false;
+ }
+ m_typesetter = CTTypesetterCreateWithAttributedString(string);
+ CFRelease(string);
+ if(!m_typesetter)
+ {
+ Clean();
+ return false;
+ }
+ m_line = CTTypesetterCreateLine(m_typesetter, CFRangeMake(0, 0));
+ if(!m_line)
+ {
+ Clean();
+ return false;
+ }
+ m_glyphs_count = CTLineGetGlyphCount(m_line);
+
+ SAL_INFO( "vcl.coretext.layout", "glyph_count=" << m_glyphs_count << " <--" );
+ return true;
+}
+
+// not needed. CoreText manage fallback directly
+void CoreTextLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
+
+// not needed. CoreText manage fallback directly
+void CoreTextLayout::Simplify( bool /*bIsBase*/ ) {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/coretext/salcoretextstyle.cxx b/vcl/coretext/salcoretextstyle.cxx
new file mode 100644
index 000000000000..b468b89782a8
--- /dev/null
+++ b/vcl/coretext/salcoretextstyle.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "coretext/common.h"
+#include "outfont.hxx"
+#include "coretext/salcoretextfontutils.hxx"
+#include "coretext/salcoretextstyle.hxx"
+
+CoreTextStyleInfo::CoreTextStyleInfo() :
+ m_fake_bold(false),
+ m_fake_italic(false),
+ m_matrix(CGAffineTransformIdentity),
+ m_stretch_factor(1.0),
+ m_CTParagraphStyle(NULL),
+ m_CTFont(NULL),
+ m_color(NULL),
+ m_font_face(NULL)
+{
+ SAL_INFO( "vcl.coretext.style", "create <-->" );
+}
+
+CoreTextStyleInfo::~CoreTextStyleInfo()
+{
+ SAL_INFO( "vcl.coretext.style", "destroy (font:" << m_CTFont << ") <-->" );
+ SafeCFRelease(m_CTFont);
+ SafeCFRelease(m_CTParagraphStyle);
+ SafeCFRelease(m_color);
+}
+
+long CoreTextStyleInfo::GetFontStretchedSize() const
+{
+ CGFloat size = CTFontGetSize(m_CTFont);
+ return static_cast<long>(size * m_stretch_factor + 0.5);
+}
+
+void CoreTextStyleInfo::SetFont(FontSelectPattern* requested_font)
+{
+ SAL_INFO( "vcl.coretext.style", "req(" << requested_font << ") release font " << m_CTFont << " -->" );
+
+ if(!requested_font)
+ {
+ SafeCFRelease(m_CTFont);
+ m_font_face = NULL;
+ return;
+ }
+ m_font_face = (CoreTextPhysicalFontFace*)(requested_font->mpFontData);
+
+ m_matrix = CGAffineTransformIdentity;
+ CGFloat font_size = (CGFloat)requested_font->mfExactHeight;
+
+ // enable bold-emulation if needed
+ if( (requested_font->GetWeight() >= WEIGHT_BOLD) &&
+ (m_font_face->GetWeight() < WEIGHT_SEMIBOLD) )
+ {
+ /* FIXME: add support for fake bold */
+ m_fake_bold = true;
+ }
+ if( ((requested_font->GetSlant() == ITALIC_NORMAL) || (requested_font->GetSlant() == ITALIC_OBLIQUE)) &&
+ !((m_font_face->GetSlant() == ITALIC_NORMAL) || (m_font_face->GetSlant() == ITALIC_OBLIQUE)) )
+ {
+#define kRotationForItalicText 10
+ m_fake_italic = true;
+ /* about 6 degree of slant */
+ m_matrix = CGAffineTransformMake( 1, 0, -tanf( kRotationForItalicText * acosf(0) / 90 ), 1, 0, 0);
+ }
+
+ // prepare font stretching
+ if( (requested_font->mnWidth != 0) && (requested_font->mnWidth != requested_font->mnHeight) )
+ {
+ m_stretch_factor = (float)requested_font->mnWidth / requested_font->mnHeight;
+ m_matrix = CGAffineTransformScale(m_matrix, m_stretch_factor, 1.0F );
+ }
+
+ SafeCFRelease(m_CTFont);
+
+ /* FIXME: pass attribute to take into accout 'VerticalStyle' */
+ /* FIXME: how to deal with 'rendering options' i.e anti-aliasing, does it even matter in CoreText ? */
+ m_CTFont = CTFontCreateCopyWithAttributes(m_font_face->GetCTFont(), font_size, &m_matrix, NULL);
+ SAL_INFO( "vcl.coretext.style", "font " << m_CTFont << " <--" );
+}
+
+void CoreTextStyleInfo::SetColor(SalColor color)
+{
+ SAL_INFO( "vcl.coretext.style", "r:" << SALCOLOR_RED(color) << ",g:" << SALCOLOR_GREEN(color) << ",b:" << SALCOLOR_BLUE(color) );
+ SafeCFRelease(m_color);
+#ifdef IOS
+ // No CGColorCreateGenericRGB on iOS
+ CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB();
+ CGFloat c[] = { SALCOLOR_RED(color) / 255.0f, SALCOLOR_GREEN(color) / 255.0f, SALCOLOR_BLUE(color) / 255.0f, 1.0 };
+ m_color = CGColorCreate(rgb_space, c);
+ CGColorSpaceRelease(rgb_space);
+#else
+ m_color = CGColorCreateGenericRGB(SALCOLOR_RED(color) / 255.0, SALCOLOR_GREEN(color) / 255.0, SALCOLOR_BLUE(color) / 255.0, 1.0);
+#endif
+ SAL_INFO( "vcl.coretext.style", "color=" << m_color << " <--" );
+}
+
+void CoreTextStyleInfo::SetColor(void)
+{
+ SAL_INFO( "vcl.coretext.style", "null -->" );
+ SafeCFRelease(m_color);
+ SAL_INFO( "vcl.coretext.style", "color=" << m_color << " <--" );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/coretext/salgdi.cxx b/vcl/coretext/salgdi.cxx
new file mode 100644
index 000000000000..ab864913a137
--- /dev/null
+++ b/vcl/coretext/salgdi.cxx
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "coretext/common.h"
+
+#ifdef MACOSX
+#include "aqua/salframe.h"
+#else
+#include "ios/salframe.h"
+#endif
+
+#include "coretext/salgdi.h"
+#include "coretext/salcoretextstyle.hxx"
+#include "coretext/salcoretextlayout.hxx"
+
+QuartzSalGraphics::QuartzSalGraphics()
+ : mpFrame( NULL )
+ , mxLayer( NULL )
+ , mrContext( NULL )
+ , mpXorEmulation( NULL )
+ , mnXorMode( 0 )
+ , mnWidth( 0 )
+ , mnHeight( 0 )
+ , mnBitmapDepth( 0 )
+ , mnRealDPIX( 0 )
+ , mnRealDPIY( 0 )
+ , mfFakeDPIScale( 1.0 )
+ , mxClipPath( NULL )
+ , maLineColor( COL_WHITE )
+ , maFillColor( COL_BLACK )
+ , mbNonAntialiasedText( false )
+ , mbPrinter( false )
+ , mbVirDev( false )
+ , mbWindow( false )
+{
+ SAL_INFO( "vcl.coretext.gr", "-->" );
+ m_style = new CoreTextStyleInfo();
+ SAL_INFO( "vcl.coretext.gr", "m_style=" << m_style << " <--" );
+}
+
+QuartzSalGraphics::~QuartzSalGraphics()
+{
+ SAL_INFO( "vcl.coretext.gr", "-->" );
+ if(m_style)
+ {
+ delete m_style;
+ m_style = NULL;
+ }
+ SAL_INFO( "vcl.coretext.gr", "<--" );
+}
+
+inline bool QuartzSalGraphics::AddTempDevFont( ImplDevFontList*,
+ const rtl::OUString& ,
+ const rtl::OUString& )
+{
+ OSL_ASSERT( FALSE );
+ return false;
+}
+
+void QuartzSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{
+}
+
+void QuartzSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
+{
+ // TODO: implementing this only makes sense when the implementation of
+ // QuartzSalGraphics::GetEmbedFontData() returns non-NULL
+ (void)pData;
+ DBG_ASSERT( (pData!=NULL), "QuartzSalGraphics::FreeEmbedFontData() is not implemented\n");
+}
+
+void QuartzSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ DBG_ASSERT( pFontList, "QuartzSalGraphics::GetDevFontList(NULL) !");
+
+ SalData* pSalData = GetSalData();
+ if (pSalData->mpFontList == NULL)
+ {
+ pSalData->mpFontList = new SystemFontList();
+ }
+ // Copy all PhysicalFontFace objects contained in the SystemFontList
+ pSalData->mpFontList->AnnounceFonts( *pFontList );
+}
+
+void QuartzSalGraphics::ClearDevFontCache()
+{
+ SalData* pSalData = GetSalData();
+ delete pSalData->mpFontList;
+ pSalData->mpFontList = NULL;
+}
+
+void QuartzSalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // nothing to do since there are no device-specific fonts on Aqua
+}
+
+const void* QuartzSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
+ const sal_Ucs* /*pUnicodes*/,
+ sal_Int32* /*pWidths*/,
+ FontSubsetInfo&,
+ long* /*pDataLen*/ )
+{
+ return NULL;
+}
+
+const Ucs2SIntMap* QuartzSalGraphics::GetFontEncodingVector(const PhysicalFontFace*,
+ const Ucs2OStrMap** /*ppNonEncoded*/ )
+{
+ return NULL;
+}
+
+void QuartzSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
+{
+ (void)nFallbackLevel; // glyph-fallback on CoreText is done differently -> no fallback level
+
+ pMetric->mbScalableFont = true;
+ pMetric->mbKernableFont = true;
+ CTFontRef font = m_style->GetFont();
+ DBG_ASSERT(font, "GetFontMetric without font set in style");
+
+ pMetric->mnAscent = static_cast<long>( CTFontGetAscent(font) * mfFakeDPIScale + 0.5);
+ pMetric->mnDescent = static_cast<long>(CTFontGetDescent(font) * mfFakeDPIScale + 0.5);
+ const long nExtDescent = static_cast<long>((CTFontGetLeading(font) + CTFontGetDescent(font)) *
+ mfFakeDPIScale + 0.5);
+ pMetric->mnExtLeading = nExtDescent + pMetric->mnDescent;
+ pMetric->mnIntLeading = 0;
+ pMetric->mnWidth = m_style->GetFontStretchedSize();
+ SAL_INFO( "vcl.coretext.gr", "ascent=" << pMetric->mnAscent<< ", descent=" << pMetric->mnDescent << ", extleading=" << pMetric->mnExtLeading << ", intleading=" << pMetric->mnIntLeading << ", w=" << pMetric->mnWidth );
+}
+
+sal_Bool QuartzSalGraphics::GetGlyphBoundRect( sal_GlyphId /*nGlyphId*/, Rectangle& /*rRect*/ )
+{
+ /* TODO: create a Ghyph iterator to keep track ot 'state' between call */
+ return false;
+}
+
+sal_Bool QuartzSalGraphics::GetGlyphOutline( sal_GlyphId /*nGlyphId*/, basegfx::B2DPolyPolygon& /*rPolyPoly*/ )
+{
+ /* TODO */
+ return false;
+}
+
+void QuartzSalGraphics::GetGlyphWidths( const PhysicalFontFace* /*pFontData*/, bool /*bVertical*/,
+ Int32Vector& /*rGlyphWidths*/, Ucs2UIntMap& /*rUnicodeEnc*/ )
+{
+}
+
+sal_uLong QuartzSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* )
+{
+ return 0;
+}
+
+bool QuartzSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+ if( !m_style )
+ {
+ return false;
+ }
+ CoreTextPhysicalFontFace* font_face = m_style->GetFontFace();
+ if( !font_face)
+ {
+ return false;
+ }
+ return font_face->GetImplFontCapabilities(rFontCapabilities);
+}
+
+const ImplFontCharMap* QuartzSalGraphics::GetImplFontCharMap() const
+{
+ if( !m_style )
+ {
+ return NULL;
+ }
+ CoreTextPhysicalFontFace* font_face = m_style->GetFontFace();
+ if( !font_face)
+ {
+ return ImplFontCharMap::GetDefaultMap();
+ }
+ return font_face->GetImplFontCharMap();
+}
+
+bool QuartzSalGraphics::GetRawFontData( const PhysicalFontFace* pFontFace,
+ std::vector<unsigned char>& rBuffer, bool* pJustCFF )
+{
+ const CoreTextPhysicalFontFace* font_face = static_cast<const CoreTextPhysicalFontFace*>(pFontFace);
+
+ return font_face->GetRawFontData(rBuffer, pJustCFF);
+}
+
+SystemFontData QuartzSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
+{
+ SAL_INFO( "vcl.coretext.gr", "-->" );
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.bAntialias = true;
+
+ CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 0.0, NULL);
+ font = (CTFontRef)CFRetain(font);
+ aSysFontData.rCTFont = font;
+
+ CTFontRef italic_font = CTFontCreateCopyWithSymbolicTraits( font,
+ 0.0,
+ NULL,
+ kCTFontItalicTrait,
+ kCTFontItalicTrait + kCTFontBoldTrait);
+ aSysFontData.bFakeItalic = italic_font ? false : true;
+ SafeCFRelease(italic_font);
+
+ CTFontRef bold_font = CTFontCreateCopyWithSymbolicTraits( font,
+ 0.0,
+ NULL,
+ kCTFontBoldTrait,
+ kCTFontItalicTrait + kCTFontBoldTrait);
+ aSysFontData.bFakeBold = bold_font ? false : true;
+ SafeCFRelease(bold_font);
+
+ CTFontRef vertical_font = CTFontCreateCopyWithSymbolicTraits( font,
+ 0.0,
+ NULL,
+ kCTFontVerticalTrait,
+ kCTFontVerticalTrait);
+ aSysFontData.bVerticalCharacterType = vertical_font ? true : false;
+ SafeCFRelease(vertical_font);
+
+ SAL_INFO( "vcl.coretext.gr", "<--" );
+ return aSysFontData;
+}
+
+SalLayout* QuartzSalGraphics::GetTextLayout( ImplLayoutArgs&, int /*nFallbackLevel*/ )
+{
+ SAL_INFO( "vcl.coretext.gr", "-->" );
+ CoreTextLayout* layout = new CoreTextLayout( this, m_style );
+ SAL_INFO( "vcl.coretext.gr", "layout:" << layout << " <--" );
+ return layout;
+}
+
+sal_uInt16 QuartzSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
+{
+ SAL_INFO( "vcl.coretext.gr", "m_style=" << m_style << " -->" );
+ m_style->SetFont(pReqFont);
+ SAL_INFO( "vcl.coretext.gr", "<--" );
+ return 0;
+}
+
+void QuartzSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ SAL_INFO( "vcl.coretext.gr", "m_style=" << m_style << " -->" );
+ m_style->SetColor(nSalColor);
+ SAL_INFO( "vcl.coretext.gr", "<--" );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */