void *quartz_new_layout(char* fontname, double fontsize, char* text)
{
	CFStringRef fontnameref = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)fontname, strlen(fontname), kCFStringEncodingUTF8, FALSE);
	CFStringRef textref = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)text, strlen(text), kCFStringEncodingUTF8, FALSE);
	CTLineRef line = NULL;
	
	if (fontnameref && textref) {
		/* set up the Core Text line */
		CTFontRef font = CTFontCreateWithName(fontnameref, fontsize, NULL);
		
		CFDictionaryRef attributes = CFDictionaryCreate(
			kCFAllocatorDefault,
			(const void**)&kCTFontAttributeName,
			(const void**)&font,
			1,
			&kCFTypeDictionaryKeyCallBacks,
			&kCFTypeDictionaryValueCallBacks);
		CFAttributedStringRef attributed = CFAttributedStringCreate(kCFAllocatorDefault, textref, attributes);
		line = CTLineCreateWithAttributedString(attributed);
		
		CFRelease(attributed);
		CFRelease(attributes);
		CFRelease(font);
	}
	
	if (textref)
		CFRelease(textref);
	if (fontnameref)
		CFRelease(fontnameref);
	return (void *)line;
}
Beispiel #2
0
void drawTextWithFeature(CGContextRef context, CTFontDescriptorRef fontDescriptor, CFStringRef feature, int value, CGPoint location)
{
    CGFloat fontSize = 25;
    CGContextSetTextMatrix(context, CGAffineTransformScale(CGAffineTransformIdentity, 1, 1));
    CGContextSetTextPosition(context, location.x, location.y);

    CFNumberRef featureValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
    CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue };
    CFTypeRef featureDictionaryValues[] = { feature, featureValue };
    CFDictionaryRef featureDictionary = CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFRelease(featureValue);

    CFTypeRef featureSettingsValues[] = { featureDictionary };
    CFArrayRef fontFeatureSettings = CFArrayCreate(kCFAllocatorDefault, featureSettingsValues, 1, &kCFTypeArrayCallBacks);
    CFRelease(featureDictionary);

    CFTypeRef fontDescriptorKeys[] = { kCTFontFeatureSettingsAttribute };
    CFTypeRef fontDescriptorValues[] = { fontFeatureSettings };
    CFDictionaryRef fontDescriptorAttributes = CFDictionaryCreate(kCFAllocatorDefault, fontDescriptorKeys, fontDescriptorValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFRelease(fontFeatureSettings);

    CTFontDescriptorRef modifiedFontDescriptor = CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fontDescriptorAttributes);
    CFRelease(fontDescriptorAttributes);

    CTFontRef font = CTFontCreateWithFontDescriptor(modifiedFontDescriptor, fontSize, nullptr);
    CFRelease(modifiedFontDescriptor);

    CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
    CFStringAppend(string, feature);
    CFStringAppend(string, value ? CFSTR("  (on)") : CFSTR(" (off)"));
    CFStringAppend(string, CFSTR(": ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));

    CGColorRef red = CGColorCreateGenericRGB(1, 0, 0, 1);
    CFTypeRef lineKeys[] = { kCTForegroundColorAttributeName };
    CFTypeRef lineValues[] = { red };
    CFDictionaryRef lineAttributes = CFDictionaryCreate(kCFAllocatorDefault, lineKeys, lineValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CGColorRelease(red);

    CFAttributedStringRef attributedString = CFAttributedStringCreate(kCFAllocatorDefault, string, lineAttributes);
    CFRelease(lineAttributes);
    CFRelease(string);

    CFMutableAttributedStringRef mutableAttributedString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, attributedString);
    CFRelease(attributedString);

    CTFontRef monospaceFont = CTFontCreateWithName(CFSTR("Courier"), fontSize, nullptr);
    CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(0, 12), kCTFontAttributeName, monospaceFont);
    CFRelease(monospaceFont);

    CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(12, 52), kCTFontAttributeName, font);
    CFRelease(font);

    CTLineRef line = CTLineCreateWithAttributedString(mutableAttributedString);
    CFRelease(mutableAttributedString);

    CTLineDraw(line, context);
    CFRelease(line);
}
Beispiel #3
0
// This function is needed to work around a bug in Windows CG <rdar://problem/22703470>
void PlatformCALayer::drawTextAtPoint(CGContextRef context, CGFloat x, CGFloat y, CGSize scale, CGFloat fontSize, const char* text, size_t length) const
{
    auto matrix = CGAffineTransformMakeScale(scale.width, scale.height);
    auto font = adoptCF(CTFontCreateWithName(CFSTR("Helvetica"), fontSize, &matrix));
    CFTypeRef keys[] = { kCTFontAttributeName, kCTForegroundColorFromContextAttributeName };
    CFTypeRef values[] = { font.get(), kCFBooleanTrue };
    auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    auto string = adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(text), length, kCFStringEncodingUTF8, false, kCFAllocatorNull));
    auto attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), attributes.get()));
    auto line = adoptCF(CTLineCreateWithAttributedString(attributedString.get()));
    CGContextSetTextPosition(context, x, y);
    CTLineDraw(line.get(), context);
}
Beispiel #4
0
xy__Float draw__string(const char *s, int x, int y, int w, float pos) {
  CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, s, kCFStringEncodingUTF8);

  if (font == NULL || font_color == NULL) {
    fprintf(stderr, "Error in %s: need both font & font_color to be non-NULL.\n", __FUNCTION__);
    return x;
  }

  CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
  CFTypeRef values[] = { font, font_color };

  CFDictionaryRef attributes =
  CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
                     (const void**)&values, sizeof(keys) / sizeof(keys[0]),
                     &kCFTypeDictionaryKeyCallBacks,
                     &kCFTypeDictionaryValueCallBacks);

  CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);
  CFRelease(string);
  CFRelease(attributes);

  CTLineRef line = CTLineCreateWithAttributedString(attrString);

  // This position set is needed to get a useful x_pos value on the next line.
  CGContextSetTextPosition(ctx, x, y);
  double x_pos = CTLineGetPenOffsetForFlush(line, pos, w);

  CGFloat descent;
  double line_width = CTLineGetTypographicBounds(line, NULL, &descent, NULL);

  CGContextSetTextPosition(ctx, x + x_pos, y + descent);

  CTLineDraw(line, ctx);
  CFRelease(line);

  return x + x_pos + line_width;
}
static OSStatus local_CoreTR(CGContextRef ctx, CGRect r, CFStringRef string,
                             CFStringRef fontName, CGFloat fontSize,
                             TRFallbackBehavior fallbackBehavior,
                             Boolean render, CGFloat baseline, TRInfo* oInfo)
{
  if (!ctx || !string || !fontName) return paramErr;
  CGContextSaveGState(ctx);
  CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
  CTFontDescriptorRef fdesc = CTFontDescriptorCreateWithNameAndSize(fontName, fontSize);
  CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL);
  CFIndex slen = CFStringGetLength(string);
  CFRange range = CFRangeMake(0L,slen);
  UniChar* buff = calloc(slen, sizeof(UniChar));
  CFStringGetCharacters(string, range, buff);
  CGGlyph* glyphs = calloc(slen, sizeof(CGGlyph));
  Boolean supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen);
  //NSLog(@"%@ supported for '%@'? %d", fontName, string, supported);
  CFRelease(fdesc);
  if (!supported)
  {
    if (fallbackBehavior == TRLastResortFallbackBehavior)
    {
      CFRelease(font);
      fdesc = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), fontSize);
      font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL);
      CFRelease(fdesc);
      supported = true;
    }
    else
    {
      CFRange rng = CFRangeMake(0L, CFStringGetLength(string));
      CTFontRef font2 = CTFontCreateForString(font, string, rng);
      CFRelease(font);
      CFStringRef fontName2 = CTFontCopyName(font2, kCTFontFullNameKey);
      fdesc = CTFontDescriptorCreateWithNameAndSize(fontName2, fontSize);
      //NSLog(@"falling back to %@ from %@ : %@", fontName2, fontName, fdesc);
      CFRelease(fontName2);
      font = CTFontCreateWithFontDescriptor(fdesc, fontSize, NULL);
      CFRelease(fdesc);
      supported = CTFontGetGlyphsForCharacters(font, buff, glyphs, slen);
    }
  }
  free(buff);
  free(glyphs);
  CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                   1L, &kCFTypeDictionaryKeyCallBacks,
                                   &kCFTypeDictionaryValueCallBacks);
  CFDictionarySetValue(attrs, kCTFontAttributeName, font);
  CFAttributedStringRef attrStr = CFAttributedStringCreate(kCFAllocatorDefault,
                                                           string, attrs);
  CFRelease(attrs);
  CTLineRef line = CTLineCreateWithAttributedString(attrStr);
  CFRelease(attrStr);
  CGRect bounds = CTLineGetImageBounds(line, ctx);
  CGFloat descent = CTFontGetDescent(font);
  CGFloat ascent = CTFontGetAscent(font);
  CFRelease(font);
  if (baseline < 0.0L)
    baseline = ((r.size.height - bounds.size.height + descent)/2.0L);
  if (render && (supported || fallbackBehavior != TRNoRenderFallbackBehavior))
  {
    CGFloat x = r.origin.x + (r.size.width/2.0L) - (bounds.size.width/2.0L) - bounds.origin.x;
    CGFloat y = r.origin.y + baseline;
    CGPoint where = CGPointMake(x, y);
    CGContextSetTextPosition(ctx, where.x, where.y);
    CTLineDraw(line, ctx);
  }
  CFRelease(line);
  if (oInfo)
  {
    oInfo->height = bounds.size.height + descent;
    oInfo->width = bounds.size.width;
    oInfo->ascent = ascent;
    oInfo->descent = descent;
    oInfo->baseline = baseline;
    oInfo->fontSupported = supported;
  }
  CGContextRestoreGState(ctx);
  return (supported)? noErr:kATSUFontsNotMatched;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

    Vector<CGGlyph, 512> glyphs(bufferLength);
    if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
        // We pass in either 256 or 512 UTF-16 characters: 256 for U+FFFF and less, 512 (double character surrogates)
        // for U+10000 and above. It is indeed possible to get back 512 glyphs back from the API, so the glyph buffer
        // we pass in must be 512. If we get back more than 256 glyphs though we'll ignore all the ones after 256,
        // this should not happen as the only time we pass in 512 characters is when they are surrogates.
        CGFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else if (!fontData->platformData().isCompositeFontReference() && ((fontData->platformData().widthVariant() == RegularWidth) ? wkGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)
               : CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength))) {
        // When buffer consists of surrogate pairs, wkGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
        // place the glyphs at indices corresponding to the first character of each pair.
        unsigned glyphStep = bufferLength / length;
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i * glyphStep])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string = adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line = adoptCF(CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to fontData->platformData().cgFont().
        RetainPtr<CGFontRef> cgFont = adoptCF(CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont = adoptCF(CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get());
            if (gotBaseFont || fontData->platformData().isCompositeFontReference()) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                if (gotBaseFont) {
                    for (CFIndex i = 0; i < glyphCount; ++i) {
                        if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                            done = true;
                            break;
                        }
                        if (glyphs[i]) {
                            setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                            haveGlyphs = true;
                        }
                    }
#if !PLATFORM(IOS)
                } else {
                    const SimpleFontData* runSimple = fontData->getCompositeFontReferenceFontData((NSFont *)runFont);
                    if (runSimple) {
                        for (CFIndex i = 0; i < glyphCount; ++i) {
                            if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                                done = true;
                                break;
                            }
                            if (glyphs[i]) {
                                setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple);
                                haveGlyphs = true;
                            }
                        }
                    }
#endif // !PLATFORM(IOS)
                }
            }
        }
    }

    return haveGlyphs;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

#ifndef BUILDING_ON_TIGER
    if (fontData->orientation() == Horizontal || fontData->isBrokenIdeographFont()) {
        Vector<CGGlyph, 512> glyphs(bufferLength);
        wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;
        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            if (CFEqual(fontData->platformData().cgFont(), runCGFont.get())) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                for (CFIndex i = 0; i < glyphCount; ++i) {
                    if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                        done = true;
                        break;
                    }
                    if (glyphs[i]) {
                        setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                        haveGlyphs = true;
                    }
                }
            }
        }
    }
#else
    // Use an array of long so we get good enough alignment.
    long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
    
    OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector);
    if (status != noErr)
        // This should never happen, perhaps indicates a bad font!  If it does the
        // font substitution code will find an alternate font.
        return false;

    wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);

    unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
    if (numGlyphs != length) {
        // This should never happen, perhaps indicates a bad font?
        // If it does happen, the font substitution code will find an alternate font.
        wkClearGlyphVector(&glyphVector);
        return false;
    }

    ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
    for (unsigned i = 0; i < length; i++) {
        Glyph glyph = glyphRecord->glyphID;
        if (!glyph)
            setGlyphDataForIndex(offset + i, 0, 0);
        else {
            setGlyphDataForIndex(offset + i, glyph, fontData);
            haveGlyphs = true;
        }
        glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
    }
    wkClearGlyphVector(&glyphVector);
#endif

    return haveGlyphs;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

    if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
        Vector<CGGlyph, 512> glyphs(bufferLength);

        CMFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
//        wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);

        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to fontData->platformData().cgFont().
        RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            if (CFEqual(cgFont.get(), runCGFont.get())) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                for (CFIndex i = 0; i < glyphCount; ++i) {
                    if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                        done = true;
                        break;
                    }
                    if (glyphs[i]) {
                        setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                        haveGlyphs = true;
                    }
                }
            }
        }
    }

    return haveGlyphs;
}
Beispiel #9
0
static bool font_renderer_create_atlas(CTFontRef face, ct_font_renderer_t *handle)
{
   int max_width, max_height;
   unsigned i;
   size_t bytesPerRow;
   CGGlyph glyphs[CT_ATLAS_SIZE];
   CGRect bounds[CT_ATLAS_SIZE];
   CGSize advances[CT_ATLAS_SIZE];
   float ascent, descent;
   CGContextRef offscreen;
   CFDictionaryRef attr;
   CFTypeRef values[1];
   CFStringRef keys[1];
   void *bitmapData                  = NULL;
   bool ret                          = true;
   size_t bitsPerComponent           = 8;
   UniChar characters[CT_ATLAS_SIZE] = {0};

   values[0]                         = face;
   keys[0]                           = kCTFontAttributeName;

   for (i = 0; i < CT_ATLAS_SIZE; i++)
      characters[i] = (UniChar)i;

   CTFontGetGlyphsForCharacters(face, characters, glyphs, CT_ATLAS_SIZE);

   CTFontGetBoundingRectsForGlyphs(face,
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
   kCTFontOrientationDefault,
#else
   kCTFontDefaultOrientation,
#endif
    glyphs, bounds, CT_ATLAS_SIZE);

   CTFontGetAdvancesForGlyphs(face,
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
         kCTFontOrientationDefault,
#else
         kCTFontDefaultOrientation, 
#endif
         glyphs, advances, CT_ATLAS_SIZE);

   ascent = CTFontGetAscent(face);
   descent = CTFontGetDescent(face);

   max_width = 0;
   max_height = 0;

   for (i = 0; i < CT_ATLAS_SIZE; i++)
   {
      int origin_x, origin_y;
      struct font_glyph *glyph = &handle->glyphs[i];

      if (!glyph)
         continue;

      origin_x             = ceil(bounds[i].origin.x);
      origin_y             = ceil(bounds[i].origin.y);

      glyph->draw_offset_x = 0;
      glyph->draw_offset_y = -ascent;
      glyph->width         = ceil(bounds[i].size.width);
      glyph->height        = ceil(bounds[i].size.height);
      glyph->advance_x     = ceil(advances[i].width);
      glyph->advance_y     = ceil(advances[i].height);

      max_width            = MAX(max_width, (origin_x + glyph->width));
      max_height           = MAX(max_height, (origin_y + glyph->height));
   }

   max_height              = MAX(max_height, ceil(ascent+descent));

   handle->atlas.width     = max_width * CT_ATLAS_COLS;
   handle->atlas.height    = max_height * CT_ATLAS_ROWS;

   handle->atlas.buffer    = (uint8_t*)
      calloc(handle->atlas.width * handle->atlas.height, 1);

   if (!handle->atlas.buffer)
   {
      ret = false;
      goto end;
   }

   bytesPerRow = max_width;
   bitmapData  = calloc(max_height, bytesPerRow);
   offscreen   = CGBitmapContextCreate(bitmapData, max_width, max_height,
            bitsPerComponent, bytesPerRow, NULL, kCGImageAlphaOnly);

   CGContextSetTextMatrix(offscreen, CGAffineTransformIdentity);

   attr = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 
         sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, 
         &kCFTypeDictionaryValueCallBacks);

   for (i = 0; i < CT_ATLAS_SIZE; i++)
   {
      char glyph_cstr[2];
      const uint8_t *src;
      uint8_t       *dst;
      unsigned offset_x, offset_y, r, c;
      CFStringRef glyph_cfstr;
      CFAttributedStringRef attrString;
      CTLineRef line;
      struct font_glyph *glyph = &handle->glyphs[i];
      
      if (!glyph)
         continue;

      glyph->width = max_width;
      glyph->height = max_height;

      offset_x = (i % CT_ATLAS_COLS) * max_width;
      offset_y = (i / CT_ATLAS_COLS) * max_height;

      glyph->atlas_offset_x = offset_x;
      glyph->atlas_offset_y = offset_y;

      glyph_cstr[0] = i;
      glyph_cstr[1] = 0;
      glyph_cfstr   = CFStringCreateWithCString(
            NULL, glyph_cstr, kCFStringEncodingASCII );
      attrString = 
         CFAttributedStringCreate(NULL, glyph_cfstr, attr);
      CFRelease(glyph_cfstr);
      glyph_cfstr = NULL;
      line = CTLineCreateWithAttributedString(attrString);
      CFRelease(attrString);
      attrString = NULL;

      memset( bitmapData, 0, max_height * bytesPerRow );
      CGContextSetTextPosition(offscreen, 0, descent);
      CTLineDraw(line, offscreen);
      CGContextFlush( offscreen );

      CFRelease( line );
      line = NULL;

      dst = (uint8_t*)handle->atlas.buffer;
      src = (const uint8_t*)bitmapData;

      for (r = 0; r < max_height; r++ )
      {
         for (c = 0; c < max_width; c++)
         {
            unsigned src_idx = r * bytesPerRow + c;
            unsigned dest_idx = 
               (r + offset_y) * (CT_ATLAS_COLS * max_width) + (c + offset_x);
            uint8_t v = src[src_idx];

            dst[dest_idx] = v;
         }
      }
   }

   CFRelease(attr);
   CGContextRelease(offscreen);

   attr = NULL;
   offscreen = NULL;
   free(bitmapData);

end:
   return ret;
}
static gboolean
run_iterator_create (struct RunIterator *iter,
                     const char         *text,
                     const gint          length,
                     CTFontRef           ctfont)
{
  char *copy;
  CFDictionaryRef attributes;
  CFAttributedStringRef attstr;

  CFTypeRef keys[] = {
      (CFTypeRef) kCTFontAttributeName
  };

  CFTypeRef values[] = {
      ctfont
  };

  /* Initialize RunIterator structure */
  iter->current_run_number = -1;
  iter->current_run = NULL;
  iter->current_indices = NULL;
  iter->current_cgglyphs = NULL;

  /* Create CTLine */
  attributes = CFDictionaryCreate (kCFAllocatorDefault,
                                   (const void **)keys,
                                   (const void **)values,
                                   1,
                                   &kCFCopyStringDictionaryKeyCallBacks,
                                   &kCFTypeDictionaryValueCallBacks);

  copy = g_strndup (text, length + 1);
  copy[length] = 0;

  iter->cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy,
                                          kCFStringEncodingUTF8);
  g_free (copy);

  if (!iter->cstr)
    /* Creating a CFString can fail if the input string does not
     * adhere to the specified encoding (i.e. it contains invalid UTF8).
     */
    return FALSE;

  attstr = CFAttributedStringCreate (kCFAllocatorDefault,
                                     iter->cstr,
                                     attributes);

  iter->line = CTLineCreateWithAttributedString (attstr);
  iter->runs = CTLineGetGlyphRuns (iter->line);

  CFRelease (attstr);
  CFRelease (attributes);

  iter->total_ct_i = 0;
  iter->glyph_count = run_iterator_get_glyph_count (iter);

  /* If CoreText did not render any glyphs for this string (can happen,
   * e.g. a run solely consisting of a BOM), glyph_count will be zero and
   * we immediately set the iterator variable to indicate end of glyph list.
   */
  if (iter->glyph_count > 0)
    run_iterator_set_current_run (iter, 0);
  else
    iter->total_ct_i = -1;

  return TRUE;
}
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const
{
    bool haveGlyphs = false;

    Vector<CGGlyph, 512> glyphs(bufferLength);
    if (!shouldUseCoreText(buffer, bufferLength, this)) {
        CGFontGetGlyphsForUnichars(platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (glyphs[i]) {
                pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this);
                haveGlyphs = true;
            }
        }
    } else if (!platformData().isCompositeFontReference() && platformData().widthVariant() != RegularWidth
        && CTFontGetGlyphsForCharacters(platformData().ctFont(), buffer, glyphs.data(), bufferLength)) {
        // When buffer consists of surrogate pairs, CTFontGetGlyphsForCharacters
        // places the glyphs at indices corresponding to the first character of each pair.
        unsigned glyphStep = bufferLength / length;
        for (unsigned i = 0; i < length; ++i) {
            if (glyphs[i * glyphStep]) {
                pageToFill->setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], this);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), getCFStringAttributes(0, hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to platformData().cgFont().
        RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get());
            if (gotBaseFont || platformData().isCompositeFontReference()) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                if (gotBaseFont) {
                    for (CFIndex i = 0; i < glyphCount; ++i) {
                        if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                            done = true;
                            break;
                        }
                        if (glyphs[i]) {
                            pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], this);
                            haveGlyphs = true;
                        }
                    }
                } else {
                    const SimpleFontData* runSimple = getCompositeFontReferenceFontData((NSFont *)runFont);
                    if (runSimple) {
                        for (CFIndex i = 0; i < glyphCount; ++i) {
                            if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                                done = true;
                                break;
                            }
                            if (glyphs[i]) {
                                pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple);
                                haveGlyphs = true;
                            }
                        }
                    }
                }
            }
        }
    }

    return haveGlyphs;
}
Beispiel #12
0
static void
basic_engine_shape (PangoEngineShape    *engine,
		    PangoFont           *font,
		    const char          *text,
		    gint                 length,
		    const PangoAnalysis *analysis,
		    PangoGlyphString    *glyphs)
{
  const char *p;
  char *copy;
  CTLineRef line;
  CFStringRef cstr;
  CFDictionaryRef attributes;
  CFAttributedStringRef attstr;
  PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font);
  PangoCoverage *coverage;
  CFArrayRef runs;
  CTRunRef run;
  CTRunStatus run_status;
  CFIndex i, glyph_count;
  const CGGlyph *cgglyphs;

  CFTypeRef keys[] = {
      (CFTypeRef) kCTFontAttributeName
  };

  CFTypeRef values[] = {
      pango_core_text_font_get_ctfont (cfont)
  };

  attributes = CFDictionaryCreate (kCFAllocatorDefault,
                                   (const void **)keys,
                                   (const void **)values,
                                   1,
                                   &kCFCopyStringDictionaryKeyCallBacks,
                                   &kCFTypeDictionaryValueCallBacks);

  copy = g_strndup (text, length + 1);
  copy[length] = 0;

  cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy,
                                    kCFStringEncodingUTF8);
  g_free (copy);

  attstr = CFAttributedStringCreate (kCFAllocatorDefault,
                                     cstr,
                                     attributes);

  line = CTLineCreateWithAttributedString (attstr);

  runs = CTLineGetGlyphRuns (line);

  /* Since Pango divides things into runs already, we assume there is
   * only a single run in this line.
   */
  run = CFArrayGetValueAtIndex (runs, 0);
  run_status = CTRunGetStatus (run);
  glyph_count = CTRunGetGlyphCount (run);
  cgglyphs = CTRunGetGlyphsPtr (run);

  p = text;
  pango_glyph_string_set_size (glyphs, glyph_count);
  coverage = pango_font_get_coverage (PANGO_FONT (cfont),
                                      analysis->language);

  for (i = 0; i < glyph_count; i++)
    {
      CFIndex real_i, prev_i;
      gunichar wc;
      gunichar mirrored_ch;

      wc = g_utf8_get_char (p);

      if (analysis->level % 2)
	if (pango_get_mirror_char (wc, &mirrored_ch))
	  wc = mirrored_ch;

      if (run_status & kCTRunStatusRightToLeft)
        {
          real_i = glyph_count - i - 1;
          prev_i = real_i + 1;
        }
      else
        {
          real_i = i;
          prev_i = real_i - 1;
        }

      if (wc == 0xa0)	/* non-break-space */
	wc = 0x20;

      if (pango_is_zero_width (wc))
	{
	  set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY);
	}
      else
	{
          PangoCoverageLevel result;

          result = pango_coverage_get (coverage, wc);

          if (result != PANGO_COVERAGE_NONE)
            {
              set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]);

              if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
                {
                  if (i > 0)
                    {
                      PangoRectangle logical_rect, ink_rect;

                      glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width,
                                                                   glyphs->glyphs[prev_i].geometry.width);
                      glyphs->glyphs[prev_i].geometry.width = 0;
                      glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i];

                      /* Some heuristics to try to guess how overstrike glyphs are
                       * done and compensate
                       */
                      pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect);
                      if (logical_rect.width == 0 && ink_rect.x == 0)
                        glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2;
                    }
                }
            }
          else
            {
              set_glyph (font, glyphs, real_i, p - text,
                         PANGO_GET_UNKNOWN_GLYPH (wc));
            }
        }

      p = g_utf8_next_char (p);
    }

  CFRelease (line);
  CFRelease (attstr);
  CFRelease (cstr);
  CFRelease (attributes);
  pango_coverage_unref (coverage);
}
Beispiel #13
0
Memsubfont*
mksubfont(XFont *f, char *name, int lo, int hi, int size, int antialias)
{
	CFStringRef s;
	CGColorSpaceRef color;
	CGContextRef ctxt;
	CTFontRef font;
	CTFontDescriptorRef desc;
	CGRect bbox;
	Memimage *m, *mc, *m1;
	int x, y, y0;
	int i, height, ascent;
	Fontchar *fc, *fc0;
	Memsubfont *sf;
	CGFloat whitef[] = { 1.0, 1.0 };
	CGColorRef white;

	s = c2mac(name);
	desc = CTFontDescriptorCreateWithNameAndSize(s, size);
	CFRelease(s);
	if(desc == nil)
		return nil;
	font = CTFontCreateWithFontDescriptor(desc, 0, nil);
	CFRelease(desc);
	if(font == nil)
		return nil;
	
	
	bbox = CTFontGetBoundingBox(font);
	x = (int)(bbox.size.width*2 + 0.99999999);

	fontheight(f, size, &height, &ascent);
	y = height;
	y0 = height - ascent;

	m = allocmemimage(Rect(0, 0, x*(hi+1-lo)+1, y+1), GREY8);
	if(m == nil)
		return nil;
	mc = allocmemimage(Rect(0, 0, x+1, y+1), GREY8);
	if(mc == nil){
		freememimage(m);
		return nil;
	}
	memfillcolor(m, DBlack);
	memfillcolor(mc, DBlack);
	fc = malloc((hi+2 - lo) * sizeof fc[0]);
	sf = malloc(sizeof *sf);
	if(fc == nil || sf == nil) {
		freememimage(m);
		freememimage(mc);
		free(fc);
		free(sf);
		return nil;
	}
	fc0 = fc;

	color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
	ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
		mc->width*sizeof(u32int), color, kCGImageAlphaNone);
	white = CGColorCreate(color, whitef);
	CGColorSpaceRelease(color);
	if(ctxt == nil) {
		freememimage(m);
		freememimage(mc);
		free(fc);
		free(sf);
		return nil;
	}

	CGContextSetAllowsAntialiasing(ctxt, antialias);
	CGContextSetTextPosition(ctxt, 0, 0);	// XXX
#if OSX_VERSION >= 101400
	CGContextSetAllowsFontSmoothing(ctxt, false);
#endif

	x = 0;
	for(i=lo; i<=hi; i++, fc++) {
		char buf[20];
		CFStringRef str;
		CFDictionaryRef attrs;
		CFAttributedStringRef attrString;
		CTLineRef line;
		CGRect r;
		CGPoint p1;
		CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
		CFTypeRef values[] = { font, white };

		sprint(buf, "%C", (Rune)mapUnicode(name, i));
 		str = c2mac(buf);
 		
 		// See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
 		attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
			(const void**)&values, sizeof(keys) / sizeof(keys[0]),
			&kCFTypeDictionaryKeyCallBacks,
			&kCFTypeDictionaryValueCallBacks);
		attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
		CFRelease(str);
		CFRelease(attrs);

		line = CTLineCreateWithAttributedString(attrString);
		CGContextSetTextPosition(ctxt, 0, y0);
		r = CTLineGetImageBounds(line, ctxt);
		memfillcolor(mc, DBlack);
		CTLineDraw(line, ctxt);		
		CFRelease(line);

		fc->x = x;
		fc->top = 0;
		fc->bottom = Dy(m->r);

//		fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y);
		p1 = CGContextGetTextPosition(ctxt);
		if(p1.x <= 0 || mapUnicode(name, i) == 0xfffd) {
			fc->width = 0;
			fc->left = 0;
			if(i == 0) {
				drawpjw(m, fc, x, (int)(bbox.size.width + 0.99999999), y, y - y0);
				x += fc->width;
			}	
			continue;
		}

		memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S);
		fc->width = p1.x;
		fc->left = 0;
		x += p1.x;
	}
	fc->x = x;

	// round up to 32-bit boundary
	// so that in-memory data is same
	// layout as in-file data.
	if(x == 0)
		x = 1;
	if(y == 0)
		y = 1;
	if(antialias)
		x += -x & 3;
	else
		x += -x & 31;
	m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
	memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
	freememimage(m);
	freememimage(mc);

	sf->name = nil;
	sf->n = hi+1 - lo;
	sf->height = Dy(m1->r);
	sf->ascent = Dy(m1->r) - y0;
	sf->info = fc0;
	sf->bits = m1;
	
	return sf;
}
Beispiel #14
0
static void
fontheight(XFont *f, int size, int *height, int *ascent)
{
	int i;
	CFStringRef s;
	CGRect bbox;
	CTFontRef font;
	CTFontDescriptorRef desc;
	CGContextRef ctxt;
	CGColorSpaceRef color;

	s = c2mac(f->name);
	desc = CTFontDescriptorCreateWithNameAndSize(s, size);
	CFRelease(s);
	if(desc == nil)
		return;
	font = CTFontCreateWithFontDescriptor(desc, 0, nil);
	CFRelease(desc);
	if(font == nil)
		return;

	color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
	ctxt = CGBitmapContextCreate(nil, 1, 1, 8, 1, color, kCGImageAlphaNone);
	CGColorSpaceRelease(color);
	CGContextSetTextPosition(ctxt, 0, 0);

	for(i=0; i<nelem(lines); i++) {
		CFStringRef keys[] = { kCTFontAttributeName };
		CFTypeRef values[] = { font };
		CFStringRef str;
		CFDictionaryRef attrs;
		CFAttributedStringRef attrString;
		CGRect r;
		CTLineRef line;

 		str = c2mac(lines[i]);
 		
 		// See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
 		attrs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
			(const void**)&values, sizeof(keys) / sizeof(keys[0]),
			&kCFTypeDictionaryKeyCallBacks,
			&kCFTypeDictionaryValueCallBacks);
		attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attrs);
		CFRelease(str);
		CFRelease(attrs);

		line = CTLineCreateWithAttributedString(attrString);
		r = CTLineGetImageBounds(line, ctxt);
		r.size.width += r.origin.x;
		r.size.height += r.origin.y;
		CFRelease(line);
		
//	fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height);
		
		if(i == 0)
			bbox = r;
		if(bbox.origin.x > r.origin.x)
			bbox.origin.x = r.origin.x;	
		if(bbox.origin.y > r.origin.y)
			bbox.origin.y = r.origin.y;	
		if(bbox.size.width < r.size.width)
			bbox.size.width = r.size.width;
		if(bbox.size.height < r.size.height)
			bbox.size.height = r.size.height;
	}

	bbox.size.width -= bbox.origin.x;
	bbox.size.height -= bbox.origin.y;

	*height = bbox.size.height + 0.999999;
	*ascent = *height - (-bbox.origin.y + 0.999999);
		
	CGContextRelease(ctxt);
	CFRelease(font);
}