diff options
Diffstat (limited to 'vcl/coretext')
-rw-r--r-- | vcl/coretext/salcoretextfontutils.cxx | 629 | ||||
-rw-r--r-- | vcl/coretext/salcoretextlayout.cxx | 485 | ||||
-rw-r--r-- | vcl/coretext/salcoretextstyle.cxx | 121 | ||||
-rw-r--r-- | vcl/coretext/salgdi.cxx | 267 |
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: */ |