blob: 0d8c895c68eb00db7e0e5afd5e38a15cca2efea8 [file] [log] [blame]
/*
* Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "FontCreator.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CoreGraphics.h>
#include <CoreServices/CoreServices.h>
#include <CoreText/CoreText.h>
#include <ImageIO/ImageIO.h>
#include <fstream>
static RetainPtr<CTFontDescriptorRef> constructFontWithTrueTypeFeature(CTFontDescriptorRef fontDescriptor, int type, int selector)
{
auto typeValue = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &type));
auto selectorValue = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &selector));
CFTypeRef featureDictionaryKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
CFTypeRef featureDictionaryValues[] = { typeValue.get(), selectorValue.get() };
auto featureDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
CFTypeRef featureSettingsValues[] = { featureDictionary.get() };
auto fontFeatureSettings = adoptCF(CFArrayCreate(kCFAllocatorDefault, featureSettingsValues, 1, &kCFTypeArrayCallBacks));
CFTypeRef fontDescriptorKeys[] = { kCTFontFeatureSettingsAttribute };
CFTypeRef fontDescriptorValues[] = { fontFeatureSettings.get() };
auto fontDescriptorAttributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, fontDescriptorKeys, fontDescriptorValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
return adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fontDescriptorAttributes.get()));
}
static RetainPtr<CTFontDescriptorRef> constructFontWithOpenTypeFeature(CTFontDescriptorRef fontDescriptor, CFStringRef feature, int value)
{
auto featureValue = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value));
CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue };
CFTypeRef featureDictionaryValues[] = { feature, featureValue.get() };
auto featureDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
CFTypeRef featureSettingsValues[] = { featureDictionary.get() };
auto fontFeatureSettings = adoptCF(CFArrayCreate(kCFAllocatorDefault, featureSettingsValues, 1, &kCFTypeArrayCallBacks));
CFTypeRef fontDescriptorKeys[] = { kCTFontFeatureSettingsAttribute };
CFTypeRef fontDescriptorValues[] = { fontFeatureSettings.get() };
auto fontDescriptorAttributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, fontDescriptorKeys, fontDescriptorValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
return adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fontDescriptorAttributes.get()));
}
static void drawText(CGContextRef context, CTFontDescriptorRef fontDescriptor, CFStringRef prefix, CGPoint location)
{
CGContextSetTextMatrix(context, CGAffineTransformScale(CGAffineTransformIdentity, 1, 1));
CGContextSetTextPosition(context, location.x, location.y);
CGFloat fontSize = 25;
auto font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, fontSize, nullptr));
auto string = adoptCF(CFStringCreateMutable(kCFAllocatorDefault, 0));
CFStringAppend(string.get(), prefix);
CFStringAppend(string.get(), CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
auto red = adoptCF(CGColorCreateGenericRGB(1, 0, 0, 1));
CFTypeRef lineKeys[] = { kCTForegroundColorAttributeName };
CFTypeRef lineValues[] = { red.get() };
auto lineAttributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, lineKeys, lineValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
auto attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), lineAttributes.get()));
auto mutableAttributedString = adoptCF(CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, attributedString.get()));
auto monospaceFont = adoptCF(CTFontCreateWithName(CFSTR("Courier"), fontSize, nullptr));
CFAttributedStringSetAttribute(mutableAttributedString.get(), CFRangeMake(0, CFStringGetLength(prefix)), kCTFontAttributeName, monospaceFont.get());
CFAttributedStringSetAttribute(mutableAttributedString.get(), CFRangeMake(CFStringGetLength(prefix), CFStringGetLength(string.get()) - CFStringGetLength(prefix)), kCTFontAttributeName, font.get());
auto line = adoptCF(CTLineCreateWithAttributedString(mutableAttributedString.get()));
CTLineDraw(line.get(), context);
}
int main(int argc, const char * argv[])
{
size_t width = 2500;
size_t height = 2000;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
auto context = adoptCF(CGBitmapContextCreate(nullptr, width, height, 8, width * 4, colorSpace, kCGImageAlphaNoneSkipLast));
CGColorSpaceRelease(colorSpace);
Type type = Type::TrueType;
const std::vector<uint8_t> fontVector = generateFont(type);
std::ofstream outputFile("/Volumes/Data/home/mmaxfield/src/WebKit/OpenSource/LayoutTests/css3/resources/FontWithFeatures.ttf", std::ios::out | std::ios::binary);
for (uint8_t b : fontVector)
outputFile << b;
outputFile.close();
auto fontData = adoptCF(CFDataCreate(kCFAllocatorDefault, fontVector.data(), fontVector.size()));
auto fontDescriptor = adoptCF(CTFontManagerCreateFontDescriptorFromData(fontData.get()));
if (type == Type::OpenType) {
CFTypeRef featureValuesOpenType[] = { CFSTR("liga"), CFSTR("clig"), CFSTR("dlig"), CFSTR("hlig"), CFSTR("calt"), CFSTR("subs"), CFSTR("sups"), CFSTR("smcp"), CFSTR("c2sc"), CFSTR("pcap"), CFSTR("c2pc"), CFSTR("unic"), CFSTR("titl"), CFSTR("onum"), CFSTR("pnum"), CFSTR("tnum"), CFSTR("frac"), CFSTR("afrc"), CFSTR("ordn"), CFSTR("zero"), CFSTR("hist"), CFSTR("jp78"), CFSTR("jp83"), CFSTR("jp90"), CFSTR("jp04"), CFSTR("smpl"), CFSTR("trad"), CFSTR("fwid"), CFSTR("pwid"), CFSTR("ruby") };
auto features = adoptCF(CFArrayCreate(kCFAllocatorDefault, featureValuesOpenType, 30, &kCFTypeArrayCallBacks));
for (CFIndex i = 0; i < CFArrayGetCount(features.get()); ++i) {
CFStringRef feature = static_cast<CFStringRef>(CFArrayGetValueAtIndex(features.get(), i));
auto modifiedFontDescriptor = constructFontWithOpenTypeFeature(fontDescriptor.get(), feature, 1);
auto prefix = adoptCF(CFStringCreateMutable(kCFAllocatorDefault, 0));
CFStringAppend(prefix.get(), feature);
CFStringAppend(prefix.get(), CFSTR(" (on): "));
drawText(context.get(), modifiedFontDescriptor.get(), prefix.get(), CGPointMake(25, 1950 - 50 * i));
modifiedFontDescriptor = constructFontWithOpenTypeFeature(fontDescriptor.get(), feature, 0);
prefix = adoptCF(CFStringCreateMutable(kCFAllocatorDefault, 0));
CFStringAppend(prefix.get(), feature);
CFStringAppend(prefix.get(), CFSTR(" (off): "));
drawText(context.get(), modifiedFontDescriptor.get(), prefix.get(), CGPointMake(25, 1925 - 50 * i));
}
} else {
__block int i = 0;
void (^handler)(uint16_t type, CFStringRef typeString, uint16_t selector, CFStringRef selectorString) = ^(uint16_t type, CFStringRef typeString, uint16_t selector, CFStringRef selectorString)
{
auto modifiedFontDescriptor = constructFontWithTrueTypeFeature(fontDescriptor.get(), type, selector);
auto prefix = adoptCF(CFStringCreateMutable(kCFAllocatorDefault, 0));
CFStringAppend(prefix.get(), typeString);
CFStringAppend(prefix.get(), CFSTR(": "));
CFStringAppend(prefix.get(), selectorString);
CFStringAppend(prefix.get(), CFSTR(": "));
while (CFStringGetLength(prefix.get()) < 65)
CFStringAppend(prefix.get(), CFSTR(" "));
drawText(context.get(), modifiedFontDescriptor.get(), prefix.get(), CGPointMake(25, 1950 - 40 * i));
++i;
};
handler(kLigaturesType, CFSTR("kLigaturesType"), kCommonLigaturesOnSelector, CFSTR("kCommonLigaturesOnSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kContextualLigaturesOnSelector, CFSTR("kContextualLigaturesOnSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kCommonLigaturesOffSelector, CFSTR("kCommonLigaturesOffSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kContextualLigaturesOffSelector, CFSTR("kContextualLigaturesOffSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kRareLigaturesOnSelector, CFSTR("kRareLigaturesOnSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kRareLigaturesOffSelector, CFSTR("kRareLigaturesOffSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kHistoricalLigaturesOnSelector, CFSTR("kHistoricalLigaturesOnSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kHistoricalLigaturesOffSelector, CFSTR("kHistoricalLigaturesOffSelector"));
handler(kContextualAlternatesType, CFSTR("kContextualAlternatesType"), kContextualAlternatesOnSelector, CFSTR("kContextualAlternatesOnSelector"));
handler(kContextualAlternatesType, CFSTR("kContextualAlternatesType"), kContextualAlternatesOffSelector, CFSTR("kContextualAlternatesOffSelector"));
handler(kVerticalPositionType, CFSTR("kVerticalPositionType"), kInferiorsSelector, CFSTR("kInferiorsSelector"));
handler(kVerticalPositionType, CFSTR("kVerticalPositionType"), kSuperiorsSelector, CFSTR("kSuperiorsSelector"));
handler(kLowerCaseType, CFSTR("kLowerCaseType"), kLowerCaseSmallCapsSelector, CFSTR("kLowerCaseSmallCapsSelector"));
handler(kUpperCaseType, CFSTR("kUpperCaseType"), kUpperCaseSmallCapsSelector, CFSTR("kUpperCaseSmallCapsSelector"));
handler(kLowerCaseType, CFSTR("kLowerCaseType"), kLowerCasePetiteCapsSelector, CFSTR("kLowerCasePetiteCapsSelector"));
handler(kUpperCaseType, CFSTR("kUpperCaseType"), kUpperCasePetiteCapsSelector, CFSTR("kUpperCasePetiteCapsSelector"));
handler(kLetterCaseType, CFSTR("kLetterCaseType"), 14, CFSTR("14"));
handler(kStyleOptionsType, CFSTR("kStyleOptionsType"), kTitlingCapsSelector, CFSTR("kTitlingCapsSelector"));
handler(kNumberCaseType, CFSTR("kNumberCaseType"), kUpperCaseNumbersSelector, CFSTR("kUpperCaseNumbersSelector"));
handler(kNumberCaseType, CFSTR("kNumberCaseType"), kLowerCaseNumbersSelector, CFSTR("kLowerCaseNumbersSelector"));
handler(kNumberSpacingType, CFSTR("kNumberSpacingType"), kProportionalNumbersSelector, CFSTR("kProportionalNumbersSelector"));
handler(kNumberSpacingType, CFSTR("kNumberSpacingType"), kMonospacedNumbersSelector, CFSTR("kMonospacedNumbersSelector"));
handler(kFractionsType, CFSTR("kFractionsType"), kDiagonalFractionsSelector, CFSTR("kDiagonalFractionsSelector"));
handler(kFractionsType, CFSTR("kFractionsType"), kVerticalFractionsSelector, CFSTR("kVerticalFractionsSelector"));
handler(kVerticalPositionType, CFSTR("kVerticalPositionType"), kOrdinalsSelector, CFSTR("kOrdinalsSelector"));
handler(kTypographicExtrasType, CFSTR("kTypographicExtrasType"), kSlashedZeroOnSelector, CFSTR("kSlashedZeroOnSelector"));
handler(kLigaturesType, CFSTR("kLigaturesType"), kHistoricalLigaturesOnSelector, CFSTR("kHistoricalLigaturesOnSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kJIS1978CharactersSelector, CFSTR("kJIS1978CharactersSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kJIS1983CharactersSelector, CFSTR("kJIS1983CharactersSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kJIS1990CharactersSelector, CFSTR("kJIS1990CharactersSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kJIS2004CharactersSelector, CFSTR("kJIS2004CharactersSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kSimplifiedCharactersSelector, CFSTR("kSimplifiedCharactersSelector"));
handler(kCharacterShapeType, CFSTR("kCharacterShapeType"), kTraditionalCharactersSelector, CFSTR("kTraditionalCharactersSelector"));
handler(kTextSpacingType, CFSTR("kTextSpacingType"), kMonospacedTextSelector, CFSTR("kMonospacedTextSelector"));
handler(kTextSpacingType, CFSTR("kTextSpacingType"), kProportionalTextSelector, CFSTR("kProportionalTextSelector"));
handler(kRubyKanaType, CFSTR("kRubyKanaType"), kRubyKanaOnSelector, CFSTR("kRubyKanaOnSelector"));
}
auto image = adoptCF(CGBitmapContextCreateImage(context.get()));
auto url = adoptCF(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/Volumes/Data/home/mmaxfield/tmp/output.png"), kCFURLPOSIXPathStyle, FALSE));
auto imageDestination = adoptCF(CGImageDestinationCreateWithURL(url.get(), kUTTypePNG, 1, nullptr));
CGImageDestinationAddImage(imageDestination.get(), image.get(), nullptr);
CGImageDestinationFinalize(imageDestination.get());
return 0;
}