office-gobmx/vcl/ios/source/gdi/salcoretextfontutils.cxx
Michael Meeks 2b4fd2c89a re-base on ALv2 code. Includes:
Patches contributed by Pedro Giffuni:
    Avoid some uses of non portable #!/bin/bash in shell scripts.
    http://svn.apache.org/viewvc?view=revision&revision=1235297
    Reduce the dependencies on non standard GNU copy.
    http://svn.apache.org/viewvc?view=revision&revision=1238684
    Correct /usr/bin/env path.
    http://svn.apache.org/viewvc?view=revision&revision=1235619

    Complex Toolbar Controls Extension from the SDK
    Patches contributed by Ariel Constenla-Haile
    http://svn.apache.org/viewvc?view=revision&revision=1190390
    i118615 - make epm more verbose
    http://svn.apache.org/viewvc?view=revision&revision=1204288

    Patches contributed by Mathias Bauer (and others)
    gnumake4 work variously
    http://svn.apache.org/viewvc?view=revision&revision=1394707
    http://svn.apache.org/viewvc?view=revision&revision=1394326

    Patches contributed by Juergen Schmidt:
    jsc341: i117327: take care if no dependency node in current
    description exists, create one
    http://svn.apache.org/viewvc?view=revision&revision=1172101
    jsc341: i117327: add extra extension dependency check
    http://svn.apache.org/viewvc?view=revision&revision=1172098
    make initial branding changes
    http://svn.apache.org/viewvc?view=revision&revision=1231878

    Patches contributed by Ingo Schmidt
    native373: #i117733# no linux jre installation on 64 bit systems
    http://svn.apache.org/viewvc?view=revision&revision=1167536
    native373: ##164464# improve debian support
    http://svn.apache.org/viewvc?view=revision&revision=1167537

    Patch contribtued by Armin Le-Grand:
    Changed various aspects concerning usages of old vendor names
    http://svn.apache.org/viewvc?view=revision&revision=1293313

fix for neon webdav, remove coinmp bits, improve odk script,
cleanup & remove OS/2 conditionals, system ucpp fixes,
remove OS/2 conditionals, restore our license filenames.
2012-11-12 11:46:43 +00:00

611 lines
19 KiB
C++

/* -*- 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 "ios/common.h"
#include "ios/salcoretextfontutils.hxx"
#include "ios/salgdi.h"
#include "sft.hxx"
#include "ios/salinst.h"
static bool GetDevFontAttributes( CTFontDescriptorRef font_descriptor, ImplDevFontAttributes& rDFA )
{
// reset the attributes
rDFA.meFamily = FAMILY_DONTKNOW;
rDFA.mePitch = PITCH_VARIABLE;
rDFA.meWidthType = WIDTH_NORMAL;
rDFA.meWeight = WEIGHT_NORMAL;
rDFA.meItalic = ITALIC_NONE;
rDFA.mbSymbolFlag = false;
rDFA.mbOrientation = true;
rDFA.mbDevice = true;
rDFA.mnQuality = 0;
CFNumberRef format = (CFNumberRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFormatAttribute);
int value = 0;
CFNumberGetValue(format, kCFNumberIntType, &value);
CFRelease(format);
if (value == kCTFontFormatBitmap)
{
/* we don't want bitmap fonts */
return false;
}
rDFA.mbSubsettable = true;
rDFA.mbEmbeddable = false;
CFStringRef family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFamilyNameAttribute);
rDFA.maName = GetOUString(family_name);
CFRelease(family_name);
CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontTraitsAttribute);
CFNumberRef symbolics = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait);
value = 0;
CFNumberGetValue(symbolics, kCFNumberIntType, &value);
CFRelease(symbolics);
if (value & kCTFontMonoSpaceTrait)
{
rDFA.mePitch = PITCH_FIXED;
}
if (value & kCTFontItalicTrait)
{
rDFA.meItalic = ITALIC_NORMAL;
}
if (value & kCTFontBoldTrait)
{
rDFA.meWeight = WEIGHT_BOLD;
}
if (value & kCTFontCondensedTrait)
{
rDFA.meWidthType = WIDTH_CONDENSED;
}
else if (value & kCTFontExpandedTrait)
{
rDFA.meWidthType = WIDTH_EXPANDED;
}
switch(value & kCTFontClassMaskTrait)
{
case kCTFontOldStyleSerifsClass:
rDFA.meFamily = FAMILY_ROMAN;
break;
case kCTFontTransitionalSerifsClass:
case kCTFontModernSerifsClass:
case kCTFontClarendonSerifsClass:
case kCTFontSlabSerifsClass:
case kCTFontFreeformSerifsClass:
break;
case kCTFontSansSerifClass:
rDFA.meFamily = FAMILY_SWISS;
case kCTFontOrnamentalsClass:
rDFA.meFamily = FAMILY_DECORATIVE;
break;
case kCTFontScriptsClass:
rDFA.meFamily = FAMILY_SCRIPT;
break;
case kCTFontSymbolicClass:
rDFA.mbSymbolFlag = true;
break;
}
CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontWeightTrait);
float fdval = 0.0;
CFNumberGetValue(weight, kCFNumberFloatType, &fdval);
if (fdval > 0.6)
{
rDFA.meWeight = WEIGHT_BLACK;
}
else if (fdval > 0.4)
{
rDFA.meWeight = WEIGHT_ULTRABOLD;
}
else if (fdval > 0.3)
{
rDFA.meWeight = WEIGHT_BOLD;
}
else if (fdval > 0.0)
{
rDFA.meWeight = WEIGHT_SEMIBOLD;
}
else if (fdval <= -0.8)
{
rDFA.meWeight = WEIGHT_ULTRALIGHT;
}
else if (fdval <= -0.4)
{
rDFA.meWeight = WEIGHT_LIGHT;
}
else if (fdval <= -0.3)
{
rDFA.meWeight = WEIGHT_SEMILIGHT;
}
else if (fdval <= -0.2)
{
rDFA.meWeight = WEIGHT_THIN;
}
else
{
rDFA.meWeight = 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.meItalic = ITALIC_OBLIQUE;
}
// heuristics to adjust font width
if (font_name_lc.indexOf("narrow") != -1)
{
rDFA.meWidthType = 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.meFamily = FAMILY_SCRIPT;
}
else if ( (font_name_lc.indexOf("comic") != -1) ||
(font_name_lc.indexOf("outline") != -1) ||
(font_name_lc.indexOf("pinpoint") != -1) )
{
rDFA.meFamily = FAMILY_DECORATIVE;
}
else if ( (font_name_lc.indexOf("sans") != -1) ||
(font_name_lc.indexOf("arial") != -1) )
{
rDFA.meFamily = FAMILY_SWISS;
}
else if ( (font_name_lc.indexOf("roman") != -1) ||
(font_name_lc.indexOf("times") != -1) )
{
rDFA.meFamily = FAMILY_ROMAN;
}
return true;
}
SystemFontList::SystemFontList()
{
CTFontCollectionRef font_collection = CTFontCollectionCreateFromAvailableFonts(NULL);
if (font_collection)
{
CFArrayRef font_descriptors = CTFontCollectionCreateMatchingFontDescriptors(font_collection);
for(int i = 0; i < CFArrayGetCount(font_descriptors); i++)
{
CTFontDescriptorRef font_descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(font_descriptors, i);
CTFontRef font = CTFontCreateWithFontDescriptor(font_descriptor, 0, NULL);
ImplDevFontAttributes devfont_attr;
if (GetDevFontAttributes( font_descriptor, devfont_attr ) )
{
ImplCoreTextFontData* font_data = new ImplCoreTextFontData(devfont_attr, font);
if (font_data && font_data->GetCTFont())
{
m_aFontContainer [ font_data->GetCTFont() ] = font_data;
}
}
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();
}
ImplCoreTextFontData* 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() );
}
}
ImplCoreTextFontData::ImplCoreTextFontData( 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 )
{
}
ImplCoreTextFontData::~ImplCoreTextFontData()
{
if ( m_pCharMap )
{
m_pCharMap->DeReference();
}
if ( m_CTFontRef )
{
CFRelease(m_CTFontRef);
}
}
PhysicalFontFace* ImplCoreTextFontData::Clone() const
{
ImplCoreTextFontData* pClone = new ImplCoreTextFontData(*this);
if ( m_pCharMap )
{
m_pCharMap->AddReference();
}
if ( m_CTFontRef )
{
pClone->m_CTFontRef = (CTFontRef)CFRetain(m_CTFontRef);
}
return pClone;
}
ImplFontEntry* ImplCoreTextFontData::CreateFontInstance(FontSelectPattern& rFSD) const
{
return new ImplFontEntry(rFSD);
}
const ImplFontCharMap* ImplCoreTextFontData::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 ImplCoreTextFontData::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 ImplCoreTextFontData::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;
}
if (CFF_table)
{
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 ImplCoreTextFontData::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 ImplCoreTextFontData::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 ImplCoreTextFontData::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: */