static OSStatus DrawGlyphBurst( DrawContextStruct *context ) { OSStatus err; ATSUTextMeasurement xPosition; ATSUTextMeasurement yPosition; Fixed numDegreesPerLine; Fixed currentDegree; ATSUAttributeTag tag = kATSULineRotationTag; ByteCount valueSize = sizeof( Fixed ); ATSUAttributeValuePtr valuePtr = ¤tDegree; // initialize the current degree to 360 degrees currentDegree = (360 << 16); // calculate the number of degrees for each glyph burst numDegreesPerLine = currentDegree / kGlyphBurstLines; // set the xPosition and the yPosition at the center of the window xPosition = ( context->bounds.size.width / 2 ); yPosition = ( context->bounds.size.height / 2 ); xPosition = xPosition << 16; yPosition = yPosition << 16; // loop through until all lines are drawn while ( currentDegree > 0 ) { // set the current rotation degree in the text layout object err = ATSUSetLayoutControls( context->layoutObject, 1, &tag, &valueSize, &valuePtr ); require_noerr( err, DrawGlyphBurst_err ); // draw! err = ATSUDrawText( context->layoutObject, kATSUFromTextBeginning, kATSUToTextEnd, xPosition, yPosition ); // decrement the current degree currentDegree -= numDegreesPerLine; } // set the current degree back to zero, in case it wasn't currentDegree = 0; err = ATSUSetLayoutControls( context->layoutObject, 1, &tag, &valueSize, &valuePtr ); require_noerr( err, DrawGlyphBurst_err ); DrawGlyphBurst_err: return err; }
static bool osx_draw_text_substring_to_cgcontext_at_location(uindex_t p_length, CGContextRef p_cgcontext, MCGPoint p_location) { if (s_layout == NULL || s_style == NULL) return false; OSStatus t_err; t_err = noErr; ATSUAttributeTag t_layout_tags[] = { kATSUCGContextTag, }; ByteCount t_layout_sizes[] = { sizeof(CGContextRef), }; ATSUAttributeValuePtr t_layout_attrs[] = { &p_cgcontext, }; if (t_err == noErr) t_err = ATSUSetLayoutControls(s_layout, sizeof(t_layout_tags) / sizeof(ATSUAttributeTag), t_layout_tags, t_layout_sizes, t_layout_attrs); if (t_err == noErr) t_err = ATSUDrawText(s_layout, 0, p_length / 2, ((int32_t)p_location . x) << 16, ((int32_t)p_location . y) << 16); return t_err == noErr; }
static void InitializeLayout() { OSStatus status = ATSUCreateTextLayout(&sTextLayout); ATSUFontFallbacks fallbacks; status = ATSUCreateFontFallbacks(&fallbacks); status = ATSUSetObjFontFallbacks(fallbacks, 0, 0, kATSULastResortOnlyFallback); ATSUAttributeTag tag = kATSULineFontFallbacksTag; ByteCount valueSize = sizeof(fallbacks); ATSUAttributeValuePtr value = &fallbacks; status = ATSUSetLayoutControls(sTextLayout, 1, &tag, &valueSize, &value); status = ATSUSetTransientFontMatching(sTextLayout, true); }
// 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); }
PlatformFont::CharInfo& MacCarbFont::getCharInfo(const UTF16 ch) const { // We use some static data here to avoid re allocating the same variable in a loop. // this func is primarily called by GFont::loadCharInfo(), Rect imageRect; CGContextRef imageCtx; U32 bitmapDataSize; ATSUTextMeasurement tbefore, tafter, tascent, tdescent; OSStatus err; // 16 bit character buffer for the ATUSI calls. // -- hey... could we cache this at the class level, set style and loc *once*, // then just write to this buffer and clear the layout cache, to speed up drawing? static UniChar chUniChar[1]; chUniChar[0] = ch; // Declare and clear out the CharInfo that will be returned. static PlatformFont::CharInfo c; dMemset(&c, 0, sizeof(c)); // prep values for GFont::addBitmap() c.bitmapIndex = 0; c.xOffset = 0; c.yOffset = 0; // put the text in the layout. // we've hardcoded a string length of 1 here, but this could work for longer strings... (hint hint) // note: ATSUSetTextPointerLocation() also clears the previous cached layout information. ATSUSetTextPointerLocation( mLayout, chUniChar, 0, 1, 1); ATSUSetRunStyle( mLayout, mStyle, 0,1); // get the typographic bounds. this tells us how characters are placed relative to other characters. ATSUGetUnjustifiedBounds( mLayout, 0, 1, &tbefore, &tafter, &tascent, &tdescent); c.xIncrement = FixedToInt(tafter); // find out how big of a bitmap we'll need. // as a bonus, we also get the origin where we should draw, encoded in the Rect. ATSUMeasureTextImage( mLayout, 0, 1, 0, 0, &imageRect); U32 xFudge = 2; U32 yFudge = 1; c.width = imageRect.right - imageRect.left + xFudge; // add 2 because small fonts don't always have enough room c.height = imageRect.bottom - imageRect.top + yFudge; c.xOrigin = imageRect.left; // dist x0 -> center line c.yOrigin = -imageRect.top; // dist y0 -> base line // kick out early if the character is undrawable if( c.width == xFudge || c.height == yFudge) return c; // allocate a greyscale bitmap and clear it. bitmapDataSize = c.width * c.height; c.bitmapData = new U8[bitmapDataSize]; dMemset(c.bitmapData,0x00,bitmapDataSize); // get a graphics context on the bitmap imageCtx = CGBitmapContextCreate( c.bitmapData, c.width, c.height, 8, c.width, mColorSpace, kCGImageAlphaNone); if(!imageCtx) { Con::errorf("Error: failed to create a graphics context on the CharInfo bitmap! Drawing a blank block."); c.xIncrement = c.width; dMemset(c.bitmapData,0x0F,bitmapDataSize); return c; } // Turn off antialiasing for monospaced console fonts. yes, this is cheating. if(mSize < 12 && ( dStrstr(mName,"Monaco")!=NULL || dStrstr(mName,"Courier")!=NULL )) CGContextSetShouldAntialias(imageCtx, false); // Set up drawing options for the context. // Since we're not going straight to the screen, we need to adjust accordingly CGContextSetShouldSmoothFonts(imageCtx, false); CGContextSetRenderingIntent(imageCtx, kCGRenderingIntentAbsoluteColorimetric); CGContextSetInterpolationQuality( imageCtx, kCGInterpolationNone); CGContextSetGrayFillColor( imageCtx, 1.0, 1.0); CGContextSetTextDrawingMode( imageCtx, kCGTextFill); // tell ATSUI to substitute fonts as needed for missing glyphs ATSUSetTransientFontMatching(mLayout, true); // set up three parrallel arrays for setting up attributes. // this is how most options in ATSUI are set, by passing arrays of options. ATSUAttributeTag theTags[] = { kATSUCGContextTag }; ByteCount theSizes[] = { sizeof(CGContextRef) }; ATSUAttributeValuePtr theValues[] = { &imageCtx }; // bind the layout to the context. ATSUSetLayoutControls( mLayout, 1, theTags, theSizes, theValues ); // Draw the character! int yoff = c.height < 3 ? 1 : 0; // kludge for 1 pixel high characters, such as '-' and '_' int xoff = 1; err = ATSUDrawText( mLayout, 0, 1, IntToFixed(-imageRect.left + xoff), IntToFixed(imageRect.bottom + yoff ) ); CGContextRelease(imageCtx); if(err != noErr) { Con::errorf("Error: could not draw the character! Drawing a blank box."); dMemset(c.bitmapData,0x0F,bitmapDataSize); } #if TORQUE_DEBUG // Con::printf("Font Metrics: Rect = %2i %2i %2i %2i Char= %C, 0x%x Size= %i, Baseline= %i, Height= %i",imageRect.top, imageRect.bottom, imageRect.left, imageRect.right,ch,ch, mSize,mBaseline, mHeight); // Con::printf("Font Bounds: left= %2i right= %2i Char= %C, 0x%x Size= %i",FixedToInt(tbefore), FixedToInt(tafter), ch,ch, mSize); #endif return c; }
void drawPlugin(NPP instance, NPCocoaEvent* event) { if (!browserUAString) return; PluginInstance* currentInstance = (PluginInstance*)(instance->pdata); CGContextRef cgContext = event->data.draw.context; if (!cgContext) return; float windowWidth = currentInstance->window.width; float windowHeight = currentInstance->window.height; // save the cgcontext gstate CGContextSaveGState(cgContext); // we get a flipped context CGContextTranslateCTM(cgContext, 0.0, windowHeight); CGContextScaleCTM(cgContext, 1.0, -1.0); // draw a gray background for the plugin CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); CGContextSetGrayFillColor(cgContext, 0.5, 1.0); CGContextDrawPath(cgContext, kCGPathFill); // draw a black frame around the plugin CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); CGContextSetGrayStrokeColor(cgContext, 0.0, 1.0); CGContextSetLineWidth(cgContext, 6.0); CGContextStrokePath(cgContext); // draw the UA string using ATSUI CGContextSetGrayFillColor(cgContext, 0.0, 1.0); ATSUStyle atsuStyle; ATSUCreateStyle(&atsuStyle); CFIndex stringLength = CFStringGetLength(browserUAString); UniChar* unicharBuffer = (UniChar*)malloc((stringLength + 1) * sizeof(UniChar)); CFStringGetCharacters(browserUAString, CFRangeMake(0, stringLength), unicharBuffer); UniCharCount runLengths = kATSUToTextEnd; ATSUTextLayout atsuLayout; ATSUCreateTextLayoutWithTextPtr(unicharBuffer, kATSUFromTextBeginning, kATSUToTextEnd, stringLength, 1, &runLengths, &atsuStyle, &atsuLayout); ATSUAttributeTag contextTag = kATSUCGContextTag; ByteCount byteSize = sizeof(CGContextRef); ATSUAttributeValuePtr contextATSUPtr = &cgContext; ATSUSetLayoutControls(atsuLayout, 1, &contextTag, &byteSize, &contextATSUPtr); ATSUTextMeasurement lineAscent, lineDescent; ATSUGetLineControl(atsuLayout, kATSUFromTextBeginning, kATSULineAscentTag, sizeof(ATSUTextMeasurement), &lineAscent, &byteSize); ATSUGetLineControl(atsuLayout, kATSUFromTextBeginning, kATSULineDescentTag, sizeof(ATSUTextMeasurement), &lineDescent, &byteSize); float lineHeight = FixedToFloat(lineAscent) + FixedToFloat(lineDescent); ItemCount softBreakCount; ATSUBatchBreakLines(atsuLayout, kATSUFromTextBeginning, stringLength, FloatToFixed(windowWidth - 10.0), &softBreakCount); ATSUGetSoftLineBreaks(atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, 0, NULL, &softBreakCount); UniCharArrayOffset* softBreaks = (UniCharArrayOffset*)malloc(softBreakCount * sizeof(UniCharArrayOffset)); ATSUGetSoftLineBreaks(atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, softBreakCount, softBreaks, &softBreakCount); UniCharArrayOffset currentDrawOffset = kATSUFromTextBeginning; int i = 0; while (i < softBreakCount) { ATSUDrawText(atsuLayout, currentDrawOffset, softBreaks[i], FloatToFixed(5.0), FloatToFixed(windowHeight - 5.0 - (lineHeight * (i + 1.0)))); currentDrawOffset = softBreaks[i]; i++; } ATSUDrawText(atsuLayout, currentDrawOffset, kATSUToTextEnd, FloatToFixed(5.0), FloatToFixed(windowHeight - 5.0 - (lineHeight * (i + 1.0)))); free(unicharBuffer); free(softBreaks); // restore the cgcontext gstate CGContextRestoreGState(cgContext); }
static bool osx_draw_text_to_cgcontext_at_location(const void *p_text, uindex_t p_length, MCGPoint p_location, const MCGFont &p_font, CGContextRef p_cgcontext, MCGIntRectangle &r_bounds) { OSStatus t_err; t_err = noErr; ATSUFontID t_font_id; Fixed t_font_size; t_font_size = p_font . size << 16; ATSUAttributeTag t_tags[] = { kATSUFontTag, kATSUSizeTag, }; ByteCount t_sizes[] = { sizeof(ATSUFontID), sizeof(Fixed), }; ATSUAttributeValuePtr t_attrs[] = { &t_font_id, &t_font_size, }; ATSLineLayoutOptions t_layout_options; ATSUAttributeTag t_layout_tags[] = { kATSULineLayoutOptionsTag, kATSUCGContextTag, }; ByteCount t_layout_sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(CGContextRef), }; ATSUAttributeValuePtr t_layout_attrs[] = { &t_layout_options, &p_cgcontext, }; if (t_err == noErr) { // if the specified fon't can't be found, just use the default if (ATSUFONDtoFontID((short)(intptr_t)p_font . fid, p_font . style, &t_font_id) != noErr) t_err = ATSUFONDtoFontID(0, p_font . style, &t_font_id); } ATSUStyle t_style; t_style = NULL; if (t_err == noErr) t_err = ATSUCreateStyle(&t_style); if (t_err == noErr) t_err = ATSUSetAttributes(t_style, sizeof(t_tags) / sizeof(ATSUAttributeTag), t_tags, t_sizes, t_attrs); ATSUTextLayout t_layout; t_layout = NULL; if (t_err == noErr) { UniCharCount t_run; t_run = p_length / 2; t_err = ATSUCreateTextLayoutWithTextPtr((const UniChar *)p_text, 0, p_length / 2, p_length / 2, 1, &t_run, &t_style, &t_layout); } if (t_err == noErr) t_err = ATSUSetTransientFontMatching(t_layout, true); if (t_err == noErr) { t_layout_options = kATSLineUseDeviceMetrics | kATSLineFractDisable; t_err = ATSUSetLayoutControls(t_layout, sizeof(t_layout_tags) / sizeof(ATSUAttributeTag), t_layout_tags, t_layout_sizes, t_layout_attrs); } MCGIntRectangle t_bounds; if (p_cgcontext == NULL) { ATSUTextMeasurement t_before, t_after, t_ascent, t_descent; if (t_err == noErr) t_err = ATSUGetUnjustifiedBounds(t_layout, 0, p_length / 2, &t_before, &t_after, &t_ascent, &t_descent); if (t_err == noErr) { t_ascent = (t_ascent + 0xffff) >> 16; t_descent = (t_descent + 0xffff) >> 16; t_after = (t_after + 0xffff) >> 16; t_bounds . x = p_location . x; t_bounds . y = p_location . y - p_font . ascent; t_bounds . width = t_after; t_bounds . height = p_font . descent + p_font . ascent; r_bounds = t_bounds; }
static OSStatus AddNewTextLayoutToContext( DrawContextStruct *context ) { OSStatus err = noErr; ATSUAttributeTag tag; ByteCount valueSize; ATSUAttributeValuePtr valuePtr; UniCharCount runLength = kATSUToTextEnd; if (context->cgContext == NULL) return err; // create a text layout object err = ATSUCreateTextLayoutWithTextPtr( context->textBuffer, kATSUFromTextBeginning, kATSUToTextEnd, context->characterCount, 1, &runLength, &gGlobalStyle, &context->layoutObject ); require_noerr( err, AddNewTextLayoutToContext_err ); // add the cgContext to the text layout tag = kATSUCGContextTag; valueSize = sizeof( CGContextRef ); valuePtr = &context->cgContext; err = ATSUSetLayoutControls( context->layoutObject, 1, &tag, &valueSize, &valuePtr ); require_noerr( err, AddNewTextLayoutToContext_err ); // set font substitution for the new layout err = ATSUSetTransientFontMatching( context->layoutObject, true ); require_noerr( err, AddNewTextLayoutToContext_err ); // now, check the menu and see if we need to install a callback switch ( gDemoMenuSelection ) { case kDemoMenuItemStretch: err = InstallStrechyGlyphCallback( context->layoutObject ); require_noerr( err, AddNewTextLayoutToContext_err ); break; case kDemoMenuItemShrink: err = InstallShrinkyGlyphCallback( context->layoutObject ); require_noerr( err, AddNewTextLayoutToContext_err ); break; case kDemoMenuItemWhitespaceReplace: err = InstallGlyphReplacementCallback( context->layoutObject ); require_noerr( err, AddNewTextLayoutToContext_err ); break; case kDemoMenuItemSineWave: err = InstallGlyphWaveCallback( context->layoutObject ); require_noerr( err, AddNewTextLayoutToContext_err ); break; case kDemoMenuItemNone: default: break; } AddNewTextLayoutToContext_err: return err; }
static OSStatus ResizeDemoWindow( EventRef inEvent, WindowRef windowRef ) { OSStatus err; Rect newBounds; Rect oldBounds; short newWidth; short newLength; HIViewRef myHIViewRef; // get the event parameter which will tell us the new size err = GetEventParameter( inEvent, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof( Rect ), NULL, &newBounds ); require_noerr( err, ResizeDemoWindow_err ); // get the old bounds, just to see if we don't need to draw anything err = GetEventParameter( inEvent, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof( Rect ), NULL, &oldBounds ); require_noerr( err, ResizeDemoWindow_err ); // calculate the new width and length newWidth = newBounds.right - newBounds.left; newLength = newBounds.bottom - newBounds.top; // check to see if we need to redraw. If this is a simple translation, // then we don't. if ( ( newLength != ( oldBounds.bottom - oldBounds.top ) ) || ( newWidth != ( oldBounds.right - oldBounds.left ) ) ) { DrawContextStruct *windowContext; CGrafPtr windowPort; // get the draw context struct from the window's refCon windowContext = (DrawContextStruct *) GetWRefCon( windowRef ); #if BUGWORKAROUNDS // get the window port windowPort = GetWindowPort( windowRef ); if (windowContext->cgContext == NULL) return err; // okay, so this is really, really lame. I'm going to get rid of // the current cg context and get a new one. This is because I // don't have the time right now to figure out how to synchronize the // clipping regions and such for the window and the context. This // is really bad, beacuse the text layout needs to have the new // cg context tag set in it, which will invalidate the layout. // I only need to dispose of the context each time until I figure // out what's going wrong with the Quickdraw clipping regions. // dispose of the context // make sure that the context is re-set in the ATSUI object if ( windowContext->layoutObject != NULL ) { ATSUAttributeTag tag = kATSUCGContextTag; ByteCount valueSize = sizeof( CGContextRef ); ATSUAttributeValuePtr valuePtr = &windowContext->cgContext; err = ATSUSetLayoutControls( windowContext->layoutObject, 1, &tag, &valueSize, &valuePtr ); require_noerr( err, ResizeDemoWindow_err ); } #endif // redraw the context HIViewFindByID(HIViewGetRoot(windowRef), myHIViewID, &myHIViewRef); HIViewSetNeedsDisplay( myHIViewRef, true); } ResizeDemoWindow_err: return eventNotHandledErr; }
bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, QShaperItem *shaperItem) const { //qDebug() << "stringToCMap" << QString(str, len); OSStatus e = noErr; e = ATSUSetTextPointerLocation(textLayout, (UniChar *)(str), 0, len, len); if (e != noErr) { qWarning("Qt: internal: %ld: Error ATSUSetTextPointerLocation %s: %d", long(e), __FILE__, __LINE__); return false; } QGlyphLayoutInfo nfo; nfo.glyphs = glyphs; nfo.numGlyphs = nglyphs; nfo.callbackCalled = false; nfo.flags = flags; nfo.shaperItem = shaperItem; QVarLengthArray<int> mappedFonts(len); for (int i = 0; i < len; ++i) mappedFonts[i] = 0; nfo.mappedFonts = mappedFonts.data(); Q_ASSERT(sizeof(void *) <= sizeof(URefCon)); e = ATSUSetTextLayoutRefCon(textLayout, (URefCon)&nfo); if (e != noErr) { qWarning("Qt: internal: %ld: Error ATSUSetTextLayoutRefCon %s: %d", long(e), __FILE__, __LINE__); return false; } { const int maxAttributeCount = 3; ATSUAttributeTag tags[maxAttributeCount + 1]; ByteCount sizes[maxAttributeCount + 1]; ATSUAttributeValuePtr values[maxAttributeCount + 1]; int attributeCount = 0; tags[attributeCount] = kATSULineLayoutOptionsTag; ATSLineLayoutOptions layopts = kATSLineHasNoOpticalAlignment | kATSLineIgnoreFontLeading | kATSLineNoSpecialJustification // we do kashidas ourselves | kATSLineDisableAllJustification ; if (!(flags & QTextEngine::DesignMetrics)) { layopts |= kATSLineFractDisable | kATSLineUseDeviceMetrics | kATSLineDisableAutoAdjustDisplayPos; } if (fontDef.styleStrategy & QFont::NoAntialias) layopts |= kATSLineNoAntiAliasing; if (!kerning) layopts |= kATSLineDisableAllKerningAdjustments; values[attributeCount] = &layopts; sizes[attributeCount] = sizeof(layopts); ++attributeCount; tags[attributeCount] = kATSULayoutOperationOverrideTag; ATSULayoutOperationOverrideSpecifier spec; spec.operationSelector = kATSULayoutOperationPostLayoutAdjustment; spec.overrideUPP = atsuPostLayoutCallback; values[attributeCount] = &spec; sizes[attributeCount] = sizeof(spec); ++attributeCount; Boolean direction; if (flags & QTextEngine::RightToLeft) direction = kATSURightToLeftBaseDirection; else direction = kATSULeftToRightBaseDirection; tags[attributeCount] = kATSULineDirectionTag; values[attributeCount] = &direction; sizes[attributeCount] = sizeof(direction); ++attributeCount; Q_ASSERT(attributeCount < maxAttributeCount + 1); e = ATSUSetLayoutControls(textLayout, attributeCount, tags, sizes, values); if (e != noErr) { qWarning("Qt: internal: %ld: Error ATSUSetLayoutControls %s: %d", long(e), __FILE__, __LINE__); return false; } } e = ATSUSetRunStyle(textLayout, style, 0, len); if (e != noErr) { qWarning("Qt: internal: %ld: Error ATSUSetRunStyle %s: %d", long(e), __FILE__, __LINE__); return false; } if (!(fontDef.styleStrategy & QFont::NoFontMerging)) { int pos = 0; do { ATSUFontID substFont = 0; UniCharArrayOffset changedOffset = 0; UniCharCount changeCount = 0; e = ATSUMatchFontsToText(textLayout, pos, len - pos, &substFont, &changedOffset, &changeCount); if (e == kATSUFontsMatched) { int fontIdx = fontIndexForFontID(substFont); for (uint i = 0; i < changeCount; ++i) mappedFonts[changedOffset + i] = fontIdx; pos = changedOffset + changeCount; ATSUSetRunStyle(textLayout, engineAt(fontIdx)->style, changedOffset, changeCount); } else if (e == kATSUFontsNotMatched) { pos = changedOffset + changeCount; } } while (pos < len && e != noErr); } { // trigger the a layout Rect rect; e = ATSUMeasureTextImage(textLayout, kATSUFromTextBeginning, kATSUToTextEnd, /*iLocationX =*/ 0, /*iLocationY =*/ 0, &rect); if (e != noErr) { qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage %s: %d", long(e), __FILE__, __LINE__); return false; } } if (!nfo.callbackCalled) { qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage did not trigger callback %s: %d", long(e), __FILE__, __LINE__); return false; } ATSUClearLayoutCache(textLayout, kATSUFromTextBeginning); return true; }
void DoAtsuiLayout(void* p, int justify) { memoryword* node = (memoryword*)p; unsigned f = native_font(node); if (fontarea[f] != AAT_FONT_FLAG) { fprintf(stderr, "internal error: do_atsui_layout called for non-ATSUI font\n"); exit(1); } if (sTextLayout == 0) InitializeLayout(); OSStatus status = noErr; long txtLen = native_length(node); const UniChar* txtPtr = (UniChar*)(node + native_node_size); status = ATSUSetTextPointerLocation(sTextLayout, txtPtr, 0, txtLen, txtLen); // we're using this font in AAT mode, so fontlayoutengine[f] is actually an ATSUStyle ATSUStyle style = (ATSUStyle)(fontlayoutengine[native_font(node)]); status = ATSUSetRunStyle(sTextLayout, style, 0, txtLen); ATSUAttributeTag tags[] = { kATSULineWidthTag, kATSULineJustificationFactorTag }; ItemCount numTags = sizeof(tags) / sizeof(ATSUAttributeTag); if (justify) { ByteCount valSizes[] = { sizeof(Fixed), sizeof(Fract) }; Fixed wid = FixedTeXtoPSPoints(node_width(node)); Fract just = fract1; ATSUAttributeValuePtr valPtrs[] = { &wid, &just }; status = ATSUSetLayoutControls(sTextLayout, numTags, tags, valSizes, valPtrs); } ItemCount count; ATSLayoutRecord* layoutRec = NULL; status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(sTextLayout, 0, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec, &count); int i; int realGlyphCount = 0; int lastRealGlyph = 0; for (i = 0; i < count; ++i) if (layoutRec[i].glyphID < 0xfffe) { lastRealGlyph = i; ++realGlyphCount; } void* glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); FixedPoint* locations = (FixedPoint*)glyph_info; UInt16* glyphIDs = (UInt16*)(locations + realGlyphCount); Fixed lsUnit = justify ? 0 : fontletterspace[f]; Fixed lsDelta = 0; realGlyphCount = 0; for (i = 0; i < count; ++i) { if (layoutRec[i].glyphID < 0xfffe) { if ((layoutRec[i].flags & kATSGlyphInfoIsAttachment) && (lsDelta != 0)) lsDelta -= lsUnit; glyphIDs[realGlyphCount] = layoutRec[i].glyphID; locations[realGlyphCount].y = 0; /* FIXME: won't handle baseline offsets */ locations[realGlyphCount].x = FixedPStoTeXPoints(layoutRec[i].realPos) + lsDelta; lsDelta += lsUnit; ++realGlyphCount; } } if (lsDelta != 0) lsDelta -= lsUnit; native_glyph_count(node) = realGlyphCount; native_glyph_info_ptr(node) = glyph_info; if (!justify) node_width(node) = FixedPStoTeXPoints(layoutRec[count-1].realPos) + lsDelta; ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec); if (justify) ATSUClearLayoutControls(sTextLayout, numTags, tags); }
OSStatus ATSTextLayoutSetContext(ATSUTextLayout lay, CGContextRef con) { ATSUAttributeTag tag[1] = {kATSUCGContextTag}; ByteCount count[1] = {sizeof(con)}; ATSUAttributeValuePtr val[1] = {con}; return ATSUSetLayoutControls( lay, 1, tag, count, val); }
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; }