MacCarbFont::~MacCarbFont() { // apple docs say we should dispose the layout first. ATSUDisposeTextLayout(mLayout); ATSUDisposeStyle(mStyle); CGColorSpaceRelease(mColorSpace); }
static void CloseDemoWindow( WindowRef windowRef ) { WindowListItem *currentItem = gWindowList; WindowListItem *previousItem = NULL; DrawContextStruct *windowContext; // search through the window list, looking for the windowRef while( currentItem != NULL ) { // check to see if the current item is the one that we're looking for if ( currentItem->windowRef == windowRef ) { // we've got a match, so set the previous item's next item pointer // to the current item's next item pointer if ( previousItem != NULL ) { previousItem->nextItem = currentItem->nextItem; } else { gWindowList = currentItem->nextItem; } // free up the current item free( currentItem ); break; } // move on to the next item previousItem = currentItem; currentItem = currentItem->nextItem; } // get the draw context struct from the window's refCon windowContext = (DrawContextStruct *) GetWRefCon( windowRef ); // if we have a context, then we need to make sure to dispose of everything // that's in the context before we free the context. if ( windowContext != NULL ) { // dispose of the text layout object if ( windowContext->layoutObject != NULL ) { verify_noerr( ATSUDisposeTextLayout( windowContext->layoutObject ) ); } // free the text buffer, if there is one if( windowContext->textBuffer != NULL ) { free( windowContext->textBuffer ); } // free the context itself free( windowContext ); } }
QFontEngineMacMulti::~QFontEngineMacMulti() { ATSUDisposeTextLayout(textLayout); ATSUDisposeStyle(style); for (int i = 0; i < engines.count(); ++i) { QFontEngineMac *fe = const_cast<QFontEngineMac *>(static_cast<const QFontEngineMac *>(engines.at(i))); fe->multiEngine = 0; if (!fe->ref.deref()) delete fe; } engines.clear(); }
extern OSStatus InvalidateAndRedrawWindows( void ) { OSStatus err = noErr; WindowListItem *currentItem = gWindowList; DrawContextStruct *windowContext; // search through the window list while( currentItem != NULL ) { // get the draw context struct from the window's refCon windowContext = (DrawContextStruct *) GetWRefCon( currentItem->windowRef ); // make sure that we have a context if ( windowContext != NULL ) { // if we have a text layout, then make sure that we get rid of it. // This really is invalidation! if ( windowContext->layoutObject != NULL ) { err = ATSUDisposeTextLayout( windowContext->layoutObject ); require_noerr( err, InvalidateAndRedrawWindows_err ); windowContext->layoutObject = NULL; } // nifty. Now, we need to redraw the window HIViewSetNeedsDisplay( ((DrawContextStruct*)GetWRefCon(currentItem->windowRef))->viewRef, true); } // grab the next context currentItem = currentItem->nextItem; } InvalidateAndRedrawWindows_err: return err; }
// This example is almost identical to the helloworld example, except that // in this case, there are two styles instead of just one. ATSUSetRunStyle // is used to apply a style to different parts of the text. // void DrawMultipleStylesContents(WindowRef window) { CFStringRef string; UniChar *text; UniCharCount length; UniCharArrayOffset currentStart, currentEnd; ATSUStyle style1, style2; ATSUTextLayout layout; ATSUFontID font; Fixed pointSize; ATSUAttributeTag tags[2]; ByteCount sizes[2]; ATSUAttributeValuePtr values[2]; Fixed lineWidth, ascent, descent; CGContextRef cgContext; float x, y, cgY, windowHeight; ItemCount numSoftBreaks; UniCharArrayOffset *theSoftBreaks; int i; GrafPtr port, savedPort; Rect portBounds; // Set up the graphics port port = GetWindowPort(window); GetPort(&savedPort); SetPort(port); GetPortBounds(port, &portBounds); EraseRect(&portBounds); // Create a style object. This is one of two objects necessary to draw using ATSUI. // (The layout is the other.) verify_noerr( ATSUCreateStyle(&style1) ); // Look up the font we are going to use, and set it in the style object, using // the aforementioned "triple" (tag, size, value) semantics. This is how almost // all settings in ATSUI are applied. verify_noerr( ATSUFindFontFromName(kMultipleStylesFontName, strlen(kMultipleStylesFontName), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &font) ); tags[0] = kATSUFontTag; sizes[0] = sizeof(ATSUFontID); values[0] = &font; verify_noerr( ATSUSetAttributes(style1, 1, tags, sizes, values) ); // Set the point size, also using a triple. You can actually set multiple triples at once, // since the tag, size, and value parameters are arrays. Other examples do this, such as // the vertical text example. // pointSize = Long2Fix(kMultipleStylesFontSize); tags[0] = kATSUSizeTag; sizes[0] = sizeof(Fixed); values[0] = &pointSize; verify_noerr( ATSUSetAttributes(style1, 1, tags, sizes, values) ); // Now we create the second of two objects necessary to draw text using ATSUI, the layout. // You can specify a pointer to the text buffer at layout creation time, or later using // the routine ATSUSetTextPointerLocation(). Below, we do it after layout creation time. verify_noerr( ATSUCreateTextLayout(&layout) ); // Before assigning text to the layout, we must first convert the string we plan to draw // from a CFStringRef into an array of UniChar. string = CFStringCreateWithCString(NULL, "In this example, various parts of the text have different styles applied. The same style is used more than once.", kCFStringEncodingASCII); // Extract the raw Unicode from the CFString, then dispose of the CFString length = CFStringGetLength(string); text = (UniChar *)malloc(length * sizeof(UniChar)); CFStringGetCharacters(string, CFRangeMake(0, length), text); CFRelease(string); // Attach the resulting UTF-16 Unicode text to the layout verify_noerr( ATSUSetTextPointerLocation(layout, text, kATSUFromTextBeginning, kATSUToTextEnd, length) ); // Now we tie the two necessary objects, the layout and the style, together verify_noerr( ATSUSetRunStyle(layout, style1, kATSUFromTextBeginning, kATSUToTextEnd) ); // Now, for this example we create a second style, and assign it to various runs within // the text. For our example, the run offsets are hard-coded for simplicity's sake. In // a real application, style runs are often assigned from external sources, such as user // selection. verify_noerr( ATSUCreateAndCopyStyle(style1, &style2) ); // Change the font for the second style verify_noerr( ATSUFindFontFromName(kMultipleStylesFontName2, strlen(kMultipleStylesFontName2), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &font) ); tags[0] = kATSUFontTag; sizes[0] = sizeof(ATSUFontID); values[0] = &font; verify_noerr( ATSUSetAttributes(style2, 1, tags, sizes, values) ); // Apply the new style to the text in various places verify_noerr( ATSUSetRunStyle(layout, style2, 8, 7) ); // The word "example" verify_noerr( ATSUSetRunStyle(layout, style2, 65, 7) ); // The word "applied" verify_noerr( ATSUSetRunStyle(layout, style2, 83, 5) ); // The word "style" verify_noerr( ATSUSetRunStyle(layout, style2, 107, 4) ); // The word "once" // In this example, we are breaking text into lines. // Therefore, we need to know the width of the line. lineWidth = X2Fix(portBounds.right - portBounds.left - 2.0*kMultipleStylesMargin); tags[0] = kATSULineWidthTag; sizes[0] = sizeof(Fixed); values[0] = &lineWidth; verify_noerr( ATSUSetLayoutControls(layout, 1, tags, sizes, values) ); // Prepare the CGContext for drawing QDBeginCGContext(port, &cgContext); tags[0] = kATSUCGContextTag; sizes[0] = sizeof(CGContextRef); values[0] = &cgContext; verify_noerr( ATSUSetLayoutControls(layout, 1, tags, sizes, values) ); // Prepare the coordinates for drawing. In our example, "x" and "y" are the coordinates // in QD space. "cgY" contains the y coordinate in CG space. // windowHeight = portBounds.bottom - portBounds.top; x = kMultipleStylesMargin; // leave a small left margin y = kMultipleStylesMargin; // leave a small top margin cgY = windowHeight - y; // Subtract the y coordinate from the height of the // window to get the coordinate in CG-aware space. // Break the text into lines verify_noerr( ATSUBatchBreakLines(layout, kATSUFromTextBeginning, length, lineWidth, &numSoftBreaks) ); verify_noerr( ATSUGetSoftLineBreaks(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, NULL, &numSoftBreaks) ); theSoftBreaks = (UniCharArrayOffset *) malloc(numSoftBreaks * sizeof(UniCharArrayOffset)); verify_noerr( ATSUGetSoftLineBreaks(layout, kATSUFromTextBeginning, kATSUToTextEnd, numSoftBreaks, theSoftBreaks, &numSoftBreaks) ); // Loop over all the lines and draw them currentStart = 0; for (i=0; i <= numSoftBreaks; i++) { currentEnd = ((numSoftBreaks > 0 ) && (numSoftBreaks > i)) ? theSoftBreaks[i] : length; // This is the height of a line, the ascent and descent. Getting the values this way is the preferred method. ATSUGetLineControl(layout, currentStart, kATSULineAscentTag, sizeof(ATSUTextMeasurement), &ascent, NULL); ATSUGetLineControl(layout, currentStart, kATSULineDescentTag, sizeof(ATSUTextMeasurement), &descent, NULL); // Make room for the area above the baseline y += Fix2X(ascent); cgY = windowHeight - y; // Draw the text verify_noerr( ATSUDrawText(layout, currentStart, currentEnd - currentStart, X2Fix(x), X2Fix(cgY)) ); // Make room for the area beloww the baseline y += Fix2X(descent); // Prepare for next line currentStart = currentEnd; } // This is a one-shot window, so we are now ready to dispose of all our objects. // Normally, we would want to keep everything around in case we needed to redraw or change // the text at some point. // Tear down the CGContext CGContextFlush(cgContext); QDEndCGContext(port, &cgContext); // Deallocate string storage free(text); // Layout and styles also need to be disposed verify_noerr( ATSUDisposeStyle(style1) ); verify_noerr( ATSUDisposeStyle(style2) ); verify_noerr( ATSUDisposeTextLayout(layout) ); // Restore the graphics port SetPort(savedPort); }
PR_CALLBACK PRIntn ATSUILayoutCache::FreeHashEntries(PLHashEntry *he, PRIntn italic, void *arg) { delete (atsuiLayoutCacheKey*)he->key; ATSUDisposeTextLayout((ATSUTextLayout)he->value); return HT_ENUMERATE_REMOVE; }
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { const char *str; bool result = false; callback->FindMissingGlyphs(&str); #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { /* Determine fallback font using CoreText. This uses the language isocode * to find a suitable font. CoreText is available from 10.5 onwards. */ char lang[16]; if (strcmp(language_isocode, "zh_TW") == 0) { /* Traditional Chinese */ strecpy(lang, "zh-Hant", lastof(lang)); } else if (strcmp(language_isocode, "zh_CN") == 0) { /* Simplified Chinese */ strecpy(lang, "zh-Hans", lastof(lang)); } else if (strncmp(language_isocode, "ur", 2) == 0) { /* The urdu alphabet is variant of persian. As OS X has no default * font that advertises an urdu language code, search for persian * support instead. */ strecpy(lang, "fa", lastof(lang)); } else { /* Just copy the first part of the isocode. */ strecpy(lang, language_isocode, lastof(lang)); char *sep = strchr(lang, '_'); if (sep != NULL) *sep = '\0'; } CFStringRef lang_code; lang_code = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8); /* Create a font iterator and iterate over all fonts that * are available to the application. */ ATSFontIterator itr; ATSFontRef font; ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsUnRestrictedScope, &itr); while (!result && ATSFontIteratorNext(itr, &font) == noErr) { /* Get CoreText font handle. */ CTFontRef font_ref = CTFontCreateWithPlatformFont(font, 0.0, NULL, NULL); CFArrayRef langs = CTFontCopySupportedLanguages(font_ref); if (langs != NULL) { /* Font has a list of supported languages. */ for (CFIndex i = 0; i < CFArrayGetCount(langs); i++) { CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(langs, i); if (CFStringCompare(lang, lang_code, kCFCompareAnchored) == kCFCompareEqualTo) { /* Lang code is supported by font, get full font name. */ CFStringRef font_name = CTFontCopyFullName(font_ref); char name[128]; CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8); CFRelease(font_name); /* Skip some inappropriate or ugly looking fonts that have better alternatives. */ if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 || strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 || strncmp(name, "GB18030 Bitmap", 14) == 0) continue; /* Save result. */ callback->SetFontNames(settings, name); DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name); result = true; break; } } CFRelease(langs); } CFRelease(font_ref); } ATSFontIteratorRelease(&itr); CFRelease(lang_code); } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !__LP64__ /* Determine fallback font using ATSUI. This uses a string sample with * missing characters. This is not failure-proof, but a better way like * using the isocode as in the CoreText code path is not available. * ATSUI was deprecated with 10.6 and is only partially available in * 64-bit mode. */ /* Remove all control characters in the range from SCC_CONTROL_START to * SCC_CONTROL_END as well as all ASCII < 0x20 from the string as it will * mess with the automatic font detection */ char buff[256]; // This length is enough to find a suitable replacement font strecpy(buff, str, lastof(buff)); str_validate(buff, lastof(buff), SVS_ALLOW_NEWLINE); /* Extract a UniChar representation of the sample string. */ CFStringRef cf_str = CFStringCreateWithCString(kCFAllocatorDefault, buff, kCFStringEncodingUTF8); if (cf_str == NULL) { /* Something went wrong. Corrupt/invalid sample string? */ return false; } CFIndex str_len = CFStringGetLength(cf_str); UniChar string[str_len]; CFStringGetCharacters(cf_str, CFRangeMake(0, str_len), string); /* Create a default text style with the default font. */ ATSUStyle style; ATSUCreateStyle(&style); /* Create a text layout object from the sample string using the text style. */ UniCharCount run_len = kATSUToTextEnd; ATSUTextLayout text_layout; ATSUCreateTextLayoutWithTextPtr(string, kATSUFromTextBeginning, kATSUToTextEnd, str_len, 1, &run_len, &style, &text_layout); /* Try to match a font for the sample text. ATSUMatchFontsToText stops after * it finds the first continuous character run not renderable with the currently * selected font starting at offset. The matching needs to be repeated until * the end of the string is reached to make sure the fallback font matches for * all characters in the string and not only the first run. */ UniCharArrayOffset offset = kATSUFromTextBeginning; OSStatus os_err; do { ATSUFontID font; UniCharCount run_len; os_err = ATSUMatchFontsToText(text_layout, offset, kATSUToTextEnd, &font, &offset, &run_len); if (os_err == kATSUFontsMatched) { /* Found a better fallback font. Update the text layout * object with the new font. */ ATSUAttributeTag tag = kATSUFontTag; ByteCount size = sizeof(font); ATSUAttributeValuePtr val = &font; ATSUSetAttributes(style, 1, &tag, &size, &val); offset += run_len; } /* Exit if the end of the string is reached or some other error occurred. */ } while (os_err == kATSUFontsMatched && offset < (UniCharArrayOffset)str_len); if (os_err == noErr || os_err == kATSUFontsMatched) { /* ATSUMatchFontsToText exited normally. Extract font * out of the text layout object. */ ATSUFontID font; ByteCount act_len; ATSUGetAttribute(style, kATSUFontTag, sizeof(font), &font, &act_len); /* Get unique font name. The result is not a c-string, we have * to leave space for a \0 and terminate it ourselves. */ char name[128]; ATSUFindFontName(font, kFontUniqueName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, 127, name, &act_len, NULL); name[act_len > 127 ? 127 : act_len] = '\0'; /* Save Result. */ callback->SetFontNames(settings, name); DEBUG(freetype, 2, "ATSUI-Font for %s: %s", language_isocode, name); result = true; } ATSUDisposeTextLayout(text_layout); ATSUDisposeStyle(style); CFRelease(cf_str); #endif } if (result && strncmp(settings->medium.font, "Geeza Pro", 9) == 0) { /* The font 'Geeza Pro' is often found for arabic characters, but * it has the 'tiny' problem of not having any latin characters. * 'Arial Unicode MS' on the other hand has arabic and latin glyphs, * but seems to 'forget' to inform the OS about this fact. Manually * substitute the latter for the former if it is loadable. */ bool ft_init = _library != NULL; FT_Face face; /* Init FreeType if needed. */ if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName("Arial Unicode MS", &face) == FT_Err_Ok) { FT_Done_Face(face); callback->SetFontNames(settings, "Arial Unicode MS"); DEBUG(freetype, 1, "Replacing font 'Geeza Pro' with 'Arial Unicode MS'"); } if (!ft_init) { /* Uninit FreeType if we did the init. */ FT_Done_FreeType(_library); _library = NULL; } } callback->FindMissingGlyphs(NULL); return result; }
void Text::calculate_position_and_advance_cursor(TextWriter &tw, int *out_x, int *out_y) const { #ifdef WIN32 const long options = DT_LEFT | DT_NOPREFIX; Context c = tw.renderer.m_context; int previous_map_mode = SetMapMode(c, MM_TEXT); HFONT font = font_handle_lookup[tw.size]; // Create the font we want to use, and swap it out with // whatever is currently in there, along with our color HFONT previous_font = (HFONT)SelectObject(c, font); // Call DrawText to find out how large our text is RECT drawing_rect = { tw.x, tw.y, 0, 0 }; tw.last_line_height = DrawText(c, m_text.c_str(), int(m_text.length()), &drawing_rect, options | DT_CALCRECT); // Return the hdc settings to their previous setting SelectObject(c, previous_font); SetMapMode(c, previous_map_mode); #else // Convert passed-in text to Unicode CFStringRef cftext = MacStringFromWide(m_text, true).get(); CFDataRef unitext = CFStringCreateExternalRepresentation(kCFAllocatorDefault, cftext, kCFStringEncodingUnicode, 0); if (!unitext) throw PianoGameError(WSTRING(L"Couldn't convert string to unicode: '" << m_text << L"'")); CFRelease(cftext); // Create an ATSU layout ATSUTextLayout layout; const UniCharCount run_length = kATSUToTextEnd; OSStatus status = ATSUCreateTextLayoutWithTextPtr((ConstUniCharArrayPtr)CFDataGetBytePtr(unitext), kATSUFromTextBeginning, kATSUToTextEnd, CFDataGetLength(unitext) / 2, 1, &run_length, &atsu_style_lookup[tw.size], &layout); if (status != noErr) throw PianoGameError(WSTRING(L"Couldn't create ATSU text layout for string: '" << m_text << L"', Error code: " << static_cast<int>(status))); // Measure the size of the resulting text Rect drawing_rect = { 0, 0, 0, 0 }; ATSUTextMeasurement before = 0; ATSUTextMeasurement after = 0; ATSUTextMeasurement ascent = 0; ATSUTextMeasurement descent = 0; status = ATSUGetUnjustifiedBounds(layout, 0, kATSUToTextEnd, &before, &after, &ascent, &descent); if (status != noErr) throw PianoGameError(WSTRING(L"Couldn't get unjustified bounds for text layout for string: '" << m_text << L"', Error code: " << static_cast<int>(status))); // NOTE: the +1 here is completely arbitrary and seemed to place the text better. // It may just be a difference between the Windows and Mac text placement systems. drawing_rect.top += tw.y + 1; drawing_rect.left += tw.x + FixRound(before); drawing_rect.right += tw.x + FixRound(after); // Not used. drawing_rect.bottom = 0; // Clean-up ATSUDisposeTextLayout(layout); CFRelease(unitext); #endif // Update the text-writer with post-draw coordinates if (tw.centered) drawing_rect.left -= (drawing_rect.right - drawing_rect.left) / 2; if (!tw.centered) tw.x += drawing_rect.right - drawing_rect.left; // Tell the draw function where to put the text *out_x = drawing_rect.left; *out_y = drawing_rect.top; }
static cairo_status_t _cairo_atsui_font_text_to_glyphs(void *abstract_font, const char *utf8, cairo_glyph_t **glyphs, int *num_glyphs) { cairo_atsui_font_t *font = abstract_font; size_t i; OSStatus err; ATSUTextLayout textLayout; ATSLayoutRecord *layoutRecords; ItemCount glyphCount; int charCount; UniChar *theText; cairo_status_t status; // liberal estimate of size charCount = strlen(utf8); if (charCount == 0) { *glyphs = NULL; *num_glyphs = 0; return CAIRO_STATUS_SUCCESS; } status = _cairo_utf8_to_utf16 (utf8, -1, &theText, &charCount); if (status) return status; err = ATSUCreateTextLayout(&textLayout); err = ATSUSetTextPointerLocation(textLayout, theText, 0, charCount, charCount); // Set the style for all of the text err = ATSUSetRunStyle(textLayout, font->unscaled_style, kATSUFromTextBeginning, kATSUToTextEnd); // Get the glyphs from the text layout object err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, 0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void *) &layoutRecords, &glyphCount); *num_glyphs = glyphCount - 1; *glyphs = (cairo_glyph_t *) malloc(*num_glyphs * (sizeof(cairo_glyph_t))); if (*glyphs == NULL) { return CAIRO_STATUS_NO_MEMORY; } for (i = 0; i < *num_glyphs; i++) { (*glyphs)[i].index = layoutRecords[i].glyphID; (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos); (*glyphs)[i].y = 0; } free(theText); ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void *) &layoutRecords); ATSUDisposeTextLayout(textLayout); return CAIRO_STATUS_SUCCESS; }
OSStatus ATSUDisposeTextLayout_wrap(ATSUTextLayout lay) { void* oText; OSStatus e = ATSUGetTextLocation(lay, &oText, NULL, NULL, NULL, NULL); if (!e) FreeHeap(oText); return ATSUDisposeTextLayout(lay); }
static OSStatus DrawLayoutForStyleAndRunInfo( ATSUStyle styleArray[], ItemCount styleArraySize, ATSUStyleRunInfo styleRunArray[], ItemCount styleRunArraySize, UniChar *stringPtr, UniCharCount stringLen, CGContextRef cgContext, Fixed currentXPos, Fixed *currentYPos ) { OSStatus err; ATSUStyle *seperateStyles = NULL; UniCharCount *seperateRunLengths = NULL; ItemCount numberOfRuns = 0; ATSUAttributeTag attrTag; ByteCount attrSize; ATSUAttributeValuePtr attrPtr; ATSUTextLayout newLayout; // check to see if we have a style array if ( styleArray != NULL ) { // if the styleRunArray is NULL, then there is only one run if ( styleRunArray == NULL ) { numberOfRuns = 1; seperateStyles = styleArray; seperateRunLengths = &stringLen; } else { ItemCount i; // the number of runs is equal to the number of runs passed in numberOfRuns = styleRunArraySize; // allocate a seperateStyles and seperateRuns array seperateStyles = (ATSUStyle *) malloc( sizeof( ATSUStyle ) * numberOfRuns ); require_action( seperateStyles != NULL, CreateLayoutForStyleAndRunInfo_err, err = memFullErr ); seperateRunLengths = (UniCharCount *) malloc( sizeof( UniCharCount ) * numberOfRuns ); require_action( seperateRunLengths != NULL, CreateLayoutForStyleAndRunInfo_err, err = memFullErr ); // loop through and assign the runs to the seperate arrays. I'm not // sure that this is the best way to do this. Perhaps it's best to // simply create the layout and assign the style runs to it individually. for ( i = 0; i < numberOfRuns; i++ ) { seperateStyles[i] = styleArray[styleRunArray[i].styleObjectIndex]; seperateRunLengths[i] = styleRunArray[i].runLength; } } } // first of all, create the layout with the text information passed in err = ATSUCreateTextLayoutWithTextPtr( stringPtr, kATSUFromTextBeginning, kATSUToTextEnd, stringLen, numberOfRuns, seperateRunLengths, seperateStyles, &newLayout ); require_noerr( err, CreateLayoutForStyleAndRunInfo_err ); // if we've got a layout, then assign the CGContext to it attrTag = kATSUCGContextTag; attrSize = sizeof( CGContextRef ); attrPtr = &cgContext; err = ATSUSetLayoutControls( newLayout, 1, &attrTag, &attrSize, &attrPtr ); require_noerr( err, CreateLayoutForStyleAndRunInfoLayout_err ); // set the Y position before we draw err = SetYPositionForLineHeight( newLayout, currentYPos ); require_noerr( err, CreateLayoutForStyleAndRunInfoLayout_err ); // do some drawin' err = ATSUDrawText( newLayout, kATSUFromTextBeginning, kATSUToTextEnd, currentXPos, *currentYPos ); require_noerr( err, CreateLayoutForStyleAndRunInfoLayout_err ); CreateLayoutForStyleAndRunInfoLayout_err: ATSUDisposeTextLayout( newLayout ); CreateLayoutForStyleAndRunInfo_err: if ( ( styleRunArray != NULL ) && ( styleArray != NULL ) ) { if ( seperateStyles != NULL ) { free( seperateStyles ); } if ( seperateRunLengths != NULL ); { free( seperateRunLengths ); } } return err; }