int getotmathitalcorr(int f, int g) { int rval = 0; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); if (table == NULL) return rval; le_uint16 offset = SWAPW(((const MathTableHeader*)table)->mathGlyphInfo); if (offset == 0) return rval; const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset); offset = SWAPW(glyphInfo->mathItalicsCorrectionInfo); if (offset == 0) return rval; const MathItalicsCorrectionInfo* italCorrInfo = (const MathItalicsCorrectionInfo*)(((const char*)glyphInfo) + offset); offset = SWAPW(italCorrInfo->coverage); if (offset == 0) return rval; const CoverageTable* coverage = (const CoverageTable*)(((const char*)italCorrInfo) + offset); le_int32 index = coverage->getGlyphCoverage(g); if (index >= 0 && index < SWAPW(italCorrInfo->italicsCorrectionCount)) rval = X2Fix(SWAPW(italCorrInfo->italicsCorrection[index].value) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } return rval; }
oop ATSUGetUnjustifiedBounds_wrap( ATSUTextLayout iTextLayout, int iLineStart, // uint32 int iLineLength, // uint32 void* FH ) { ATSUTextMeasurement oTextBefore, oTextAfter, oAscent, oDescent; OSStatus e = ATSUGetUnjustifiedBounds( iTextLayout, (uint32)iLineStart, (uint32)iLineLength, &oTextBefore, &oTextAfter, &oAscent, &oDescent ); if (e != noErr) { return (oop)reportOSError(e, "ATSUGetUnjustifiedBounds", FH); } objVectorOop r = Memory->objVectorObj->cloneSize(4); r->obj_at_put(0, as_floatOop(Fix2X(oTextBefore)), false); r->obj_at_put(1, as_floatOop(Fix2X(oAscent)), false); r->obj_at_put(2, as_floatOop(Fix2X(oTextAfter)), false); r->obj_at_put(3, as_floatOop(Fix2X(oDescent)), false); return r; }
int otpartfulladvance(int f, const GlyphAssembly* a, int i) { int rval = 0; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = X2Fix(SWAPW(a->partRecords[i].fullAdvance) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } return rval; }
int getotmathconstant(int f, int n) { int rval = 0; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = getMathConstant(font, (mathConstantIndex)n); /* scale according to font size, except the ones that are percentages */ if (n > scriptScriptPercentScaleDown && n < radicalDegreeBottomRaisePercent) rval = X2Fix(rval * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } return rval; }
// Checks the global preference to see if text at the specified point size // will be drawn antialiased or not. // // Note that iSize is of type Fixed! // Boolean IsAntiAliased(Fixed iSize) { Boolean keyExistsAndHasValidFormat; CFIndex value; value = CFPreferencesGetAppIntegerValue( CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat ); if ( keyExistsAndHasValidFormat ) return ( Fix2X(iSize) > value ); // 'value' is the maximum not-antialiasing size else return true; }
/*------------------------------------ cmd_Volumeq ---*/ Pvoid cmd_Volumeq(SpeakPtr xx) { EnterCallback(); if (xx && xx->fSpeaker) { Atom response[1]; Fixed volume; GetSpeechInfo(xx->fSpeaker, soVolume, &volume); SETFLOAT(response, float(Fix2X(volume))); outlet_anything(xx->fResultOut, gVolumeSymbol, 1, response); } ExitMaxMessageHandler() } /* cmd_Volumeq */
void XeTeXFontMgr::getOpSizeRecAndStyleFlags(Font* theFont) { XeTeXFont font = createFont(theFont->fontRef, 655360); if (font != 0) { const OpSizeRec* pSizeRec = getOpSizePtr(font); if (pSizeRec != NULL) { theFont->opSizeInfo.designSize = SWAP(pSizeRec->designSize); if (SWAP(pSizeRec->subFamilyID) == 0 && SWAP(pSizeRec->nameCode) == 0 && SWAP(pSizeRec->minSize) == 0 && SWAP(pSizeRec->maxSize) == 0) goto done_size; // feature is valid, but no 'size' range theFont->opSizeInfo.subFamilyID = SWAP(pSizeRec->subFamilyID); theFont->opSizeInfo.nameCode = SWAP(pSizeRec->nameCode); theFont->opSizeInfo.minSize = SWAP(pSizeRec->minSize); theFont->opSizeInfo.maxSize = SWAP(pSizeRec->maxSize); } done_size: const OS2TableHeader* os2Table = (const OS2TableHeader*)getFontTablePtr(font, LE_OS_2_TABLE_TAG); if (os2Table != NULL) { theFont->weight = SWAP(os2Table->usWeightClass); theFont->width = SWAP(os2Table->usWidthClass); UInt16 sel = SWAP(os2Table->fsSelection); theFont->isReg = (sel & (1 << 6)) != 0; theFont->isBold = (sel & (1 << 5)) != 0; theFont->isItalic = (sel & (1 << 0)) != 0; } const HEADTable* headTable = (const HEADTable*)getFontTablePtr(font, LE_HEAD_TABLE_TAG); if (headTable != NULL) { UInt16 ms = SWAP(headTable->macStyle); if ((ms & (1 << 0)) != 0) theFont->isBold = true; if ((ms & (1 << 1)) != 0) theFont->isItalic = true; } const POSTTable* postTable = (const POSTTable*)getFontTablePtr(font, LE_POST_TABLE_TAG); if (postTable != NULL) { theFont->slant = (int)(1000 * (tan(Fix2X(-SWAP(postTable->italicAngle)) * M_PI / 180.0))); } deleteFont(font); } }
oop ATSUGetGlyphBounds_wrap( ATSUTextLayout iTextLayout, float fTextBasePointX, float fTextBasePointY, int iBoundsCharStart, // uint32 int iBoundsCharLength, // uint32 uint16 iTypeOfBounds, void* FH ) { ATSUTextMeasurement iTextBasePointX = X2Fix(fTextBasePointX); ATSUTextMeasurement iTextBasePointY = X2Fix(fTextBasePointY); ATSTrapezoid b; ItemCount oActualNumberOfBounds; OSStatus e = ATSUGetGlyphBounds( iTextLayout, iTextBasePointX, iTextBasePointY, iBoundsCharStart, iBoundsCharLength, iTypeOfBounds, 1, // ItemCount iMaxNumberOfBounds, &b, &oActualNumberOfBounds); /* can be NULL */ if (e != noErr) { return (oop)reportOSError(e, "ATSUGetGlyphBounds", FH); } if (oActualNumberOfBounds < 1) { static char buf[1000]; sprintf(buf, "ATSUGetGlyphBounds failed: returned %d bounds instead of 1", (int)oActualNumberOfBounds); failure(FH, buf); return NULL; } float L = min((float)Fix2X(b.upperLeft.x), (float)Fix2X(b.lowerLeft.x )); float T = max((float)Fix2X(b.upperLeft.y), (float)Fix2X(b.upperRight.y)); float R = min((float)Fix2X(b.upperRight.x), (float)Fix2X(b.lowerRight.x)); float B = max((float)Fix2X(b.lowerLeft.y ), (float)Fix2X(b.lowerRight.y)); objVectorOop r = Memory->objVectorObj->cloneSize(4); r->obj_at_put(0, as_floatOop(L), false); r->obj_at_put(1, as_floatOop(T), false); r->obj_at_put(2, as_floatOop(R), false); r->obj_at_put(3, as_floatOop(B), false); return r; }
P1(PUBLIC pascal trap, Fract, FracSin, Fixed, x) /* IMIV-64 */ { Extended z; LONGINT oct; if (x < 0) x += (-(x+1) / (POVER4 * 8) + 1) * POVER4 * 8; oct = x / POVER4 % 8; x %= POVER4 * 4; switch (oct) { case 0: z = sin(Fix2X(x)); break; case 1: z = cos(Fix2X(POVER4 * 2 - x)); break; case 2: z = cos(Fix2X(x - POVER4 * 2)); break; case 3: z = sin(Fix2X(POVER4 * 4 - x)); break; case 4: z = -sin(Fix2X(x)); break; case 5: z = -cos(Fix2X(POVER4 * 2 - x)); break; case 6: z = -cos(Fix2X(x - POVER4 * 2)); break; case 7: z = -sin(Fix2X(POVER4 * 4 - x)); break; } return X2Frac(&z); }
int getotmathvariant(int f, int g, int v, integer* adv, int horiz) { int rval = g; *adv = -1; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); if (table == NULL) return rval; le_uint16 offset = SWAPW(((const MathTableHeader*)table)->mathVariants); if (offset == 0) return rval; const MathVariants* variants = (const MathVariants*)(table + offset); offset = horiz ? SWAPW(variants->horizGlyphCoverage) : SWAPW(variants->vertGlyphCoverage); if (offset == 0) return rval; const CoverageTable* coverage = (const CoverageTable*)(((const char*)variants) + offset); le_int32 index = coverage->getGlyphCoverage(g); if (index >= 0) { if (horiz) index += SWAPW(variants->vertGlyphCount); const MathGlyphConstruction* construction = (const MathGlyphConstruction*)(((const char*)variants) + SWAPW(variants->vertGlyphConstruction[index])); if (v < SWAPW(construction->variantCount)) { rval = SWAPW(construction->mathGlyphVariantRecord[v].variantGlyph); *adv = X2Fix(SWAPW(construction->mathGlyphVariantRecord[v].advanceMeasurement) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } } } return rval; }
int otminconnectoroverlap(int f) { int rval = 0; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); if (table == NULL) return rval; le_uint16 offset = SWAPW(((const MathTableHeader*)table)->mathVariants); if (offset == 0) return rval; const MathVariants* variants = (const MathVariants*)(table + offset); rval = X2Fix(SWAPW(variants->minConnectorOverlap) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } return rval; }
/* Calculate the static frame rate for a given movie. */ void MovieGetStaticFrameRate(Movie inMovie, double *outStaticFrameRate) { *outStaticFrameRate = 0; Media movieMedia; MediaHandler movieMediaHandler; /* get the media identifier for the media that contains the first video track's sample data, and also get the media handler for this media. */ MovieGetVideoMediaAndMediaHandler(inMovie, &movieMedia, &movieMediaHandler); if (movieMedia && movieMediaHandler) { Boolean isMPEG = false; /* is this the MPEG-1/MPEG-2 media handler? */ OSErr err = IsMPEGMediaHandler(movieMediaHandler, &isMPEG); if (err == noErr) { if (isMPEG) /* working with MPEG-1/MPEG-2 media */ { Fixed staticFrameRate; ComponentResult err = MPEGMediaGetStaticFrameRate(movieMediaHandler, &staticFrameRate); if (err == noErr) { /* convert Fixed data result to type double */ *outStaticFrameRate = Fix2X(staticFrameRate); } } else /* working with non-MPEG-1/MPEG-2 media */ { OSErr err = MediaGetStaticFrameRate(movieMedia, outStaticFrameRate); if (err != noErr) ofLog(OF_LOG_ERROR, "error in MediaGetStaticFrameRate, ofQtUtils"); //assert(err == noErr); } } } }
int getotmathaccentpos(int f, int g) { int rval = 0x7fffffffUL; if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); if (table == NULL) return rval; le_uint16 offset = SWAPW(((const MathTableHeader*)table)->mathGlyphInfo); if (offset == 0) return rval; const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset); offset = SWAPW(glyphInfo->mathTopAccentAttachment); if (offset == 0) return rval; const MathTopAccentAttachment* accentAttachment = (const MathTopAccentAttachment*)(((const char*)glyphInfo) + offset); offset = SWAPW(accentAttachment->coverage); if (offset == 0) return rval; const CoverageTable* coverage = (const CoverageTable*)(((const char*)accentAttachment) + offset); le_int32 index = coverage->getGlyphCoverage(g); if (index >= 0 && index < SWAPW(accentAttachment->topAccentAttachmentCount)) { rval = (le_int16)SWAPW(accentAttachment->topAccentAttachment[index].value); rval = X2Fix(rval * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } } return rval; }
// 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); }
static inline Fixed FixedTeXtoPSPoints(Fixed pts) { return X2Fix(TeXtoPSPoints(Fix2X(pts))); }
// Draws the current ATSUI data. Takes a GrafPtr as an argument so // that it can handle printing as well as drawing into a window. // void DrawATSUIStuff(GrafPtr drawingPort) { GrafPtr savedPort; Rect portBounds, quarterRect2, quarterRect3; float windowHeight, quarter; CGContextRef context; TXNTextBoxOptionsData optionsData; Boolean needToUseCGStrokeMethod; // Set up the GrafPort GetPort(&savedPort); SetPort(drawingPort); GetPortBounds(drawingPort, &portBounds); EraseRect(&portBounds); // Divide the window into vertical quarters, and draw the text in the middle two quarters windowHeight = portBounds.bottom - portBounds.top; quarter = windowHeight / 4.0; MacSetRect(&quarterRect2, portBounds.left, portBounds.top + quarter, portBounds.right, portBounds.bottom - (quarter * 2.0)); FrameRect(&quarterRect2); MacSetRect(&quarterRect3, portBounds.left, portBounds.top + (quarter * 2.0), portBounds.right, portBounds.bottom - quarter); FrameRect(&quarterRect3); // Set up the CGContext if (gNewCG) QDBeginCGContext(drawingPort, &context); else CreateCGContextForPort(drawingPort, &context); // Setup the options to pass into TXNDrawUnicodeTextBox optionsData.optionTags = kTXNUseCGContextRefMask | kTXNSetFlushnessMask | kTXNUseFontFallBackMask; optionsData.flushness = X2Frac(0.5); // Center the text horizontally, just for this demo. optionsData.options = (void *)context; // This parameter really needs to be renamed, see 3198383. // Draw the text once without the extr bold verify_noerr( TXNDrawUnicodeTextBox(gText, gLength, &quarterRect2, gStyle, &optionsData) ); // ---------------------------------------------------------- // // Here is where we change the setting to do the extra stroke // The value of gStrokeThicknessFactor determines how thick the extra stroke is. // The "standard" value used by ATSUI is 0.024; // this was changed to 0.044 for bug 3189696, // and will probably be changed back, so if you // want the extra stroke, you will have to do it // manually, as is done below. // // The extra stroke method: // - will look good on-screen when CG anti-aliasing is ON // - will look good when printing // - will *NOT* look good on-screen when CG anti-aliasing is OFF // (just use kATSUQDBoldfaceTag in that case) // needToUseCGStrokeMethod = gCurrentlyPrinting || IsAntiAliased(gPointSize); if ( needToUseCGStrokeMethod ) { CGContextSaveGState(context); CGContextSetTextDrawingMode(context, kCGTextFillStroke); CGContextSetLineWidth(context, gStrokeThicknessFactor * Fix2X(gPointSize)); // You might want to call CGContextSetStrokeColor() here, // just to make certain it is the same as the text/fill color. } else MySetBoldfaceTag(gStyle); // This will look very strong on-screen when CG anti-aliasing is off // Draw the text again with the extra bold for comparison verify_noerr( TXNDrawUnicodeTextBox(gText, gLength, &quarterRect3, gStyle, &optionsData) ); // Undo the previous CG text mode setting if ( needToUseCGStrokeMethod ) CGContextRestoreGState(context); else MyClearBoldfaceTag(gStyle); // Tear down the CGContext since we are done with it if (gNewCG) QDEndCGContext(drawingPort, &context); else CGContextRelease(context); // Restore the GrafPort SetPort(savedPort); }
static inline Fixed FixedPStoTeXPoints(Fixed pts) { return X2Fix(PStoTeXPoints(Fix2X(pts))); }
PsychError SCREENTextBounds(void) { //for debugging TextEncodingBase textEncodingBase; TextEncodingVariant textEncodingVariant; TextEncodingFormat textEncodingFormat; /////// PsychWindowRecordType *winRec; char *textCString; Str255 textPString; UniChar *textUniString; OSStatus callError; PsychRectType resultPsychRect, resultPsychNormRect; ATSUTextLayout textLayout; //layout is a pointer to an opaque struct. int stringLengthChars; int uniCharBufferLengthElements, uniCharBufferLengthChars, uniCharBufferLengthBytes, yPositionIsBaseline; double textHeightToBaseline; ByteCount uniCharStringLengthBytes; TextToUnicodeInfo textToUnicodeInfo; TextEncoding textEncoding; ATSUStyle atsuStyle; Boolean foundFont; //for ATSU style attributes PsychFontStructPtrType psychFontRecord; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; //check for correct the number of arguments before getting involved PsychErrorExit(PsychCapNumInputArgs(5)); PsychErrorExit(PsychRequireNumInputArgs(2)); PsychErrorExit(PsychCapNumOutputArgs(2)); //get the window pointer and the text string and check that the window record has a font set PsychAllocInWindowRecordArg(1, kPsychArgRequired, &winRec); foundFont=PsychGetFontRecordFromFontNumber(winRec->textAttributes.textFontNumber, &psychFontRecord); if(!foundFont) PsychErrorExitMsg(PsychError_user, "Attempt to determine the bounds of text with no font or invalid font number"); //it would be better to both prevent the user from setting invalid font numbers and init to the OS 9 default font. //read in the string and get its length and convert it to a unicode string. PsychAllocInCharArg(2, kPsychArgRequired, &textCString); stringLengthChars=strlen(textCString); if(stringLengthChars < 1) PsychErrorExitMsg(PsychError_user, "You asked me to compute the bounding box of an empty text string?!? Sorry, that's a no no..."); if(stringLengthChars > 255) PsychErrorExitMsg(PsychError_unimplemented, "Cut corners and TextBounds will not accept a string longer than 255 characters"); CopyCStringToPascal(textCString, textPString); uniCharBufferLengthChars= stringLengthChars * CHAR_TO_UNICODE_LENGTH_FACTOR; uniCharBufferLengthElements= uniCharBufferLengthChars + 1; uniCharBufferLengthBytes= sizeof(UniChar) * uniCharBufferLengthElements; textUniString=(UniChar*)malloc(uniCharBufferLengthBytes); PsychCopyInDoubleArg(3, kPsychArgOptional, &(winRec->textAttributes.textPositionX)); PsychCopyInDoubleArg(4, kPsychArgOptional, &(winRec->textAttributes.textPositionY)); //Using a TextEncoding type describe the encoding of the text to be converteed. textEncoding=CreateTextEncoding(kTextEncodingMacRoman, kMacRomanDefaultVariant, kTextEncodingDefaultFormat); //Take apart the encoding we just made to check it: textEncodingBase=GetTextEncodingBase(textEncoding); textEncodingVariant=GetTextEncodingVariant(textEncoding); textEncodingFormat=GetTextEncodingFormat(textEncoding); //Create a structure holding conversion information from the text encoding type we just created. callError=CreateTextToUnicodeInfoByEncoding(textEncoding,&textToUnicodeInfo); //Convert the text to a unicode string callError=ConvertFromPStringToUnicode(textToUnicodeInfo, textPString, (ByteCount)uniCharBufferLengthBytes, &uniCharStringLengthBytes, textUniString); //create the text layout object callError=ATSUCreateTextLayout(&textLayout); //associate our unicode text string with the text layout object callError=ATSUSetTextPointerLocation(textLayout, textUniString, kATSUFromTextBeginning, kATSUToTextEnd, (UniCharCount)stringLengthChars); //create an ATSU style object callError=ATSUCreateStyle(&atsuStyle); callError=ATSUClearStyle(atsuStyle); //Not that we have a style object we have to set style charactersitics. These include but are more general than Font Manager styles. //ATSU Style objects have three sets of characteristics: attributes, variations, and features. //attributes are things we need to set to match OS 9 behavior, such as the font ID, size, boldness, and italicization. //features are esoteric settings which we don't need for reproducing OS 9 behavior. Whatever clearstyle sets should be fine. //font variations are axes of variation through the space of font characteristics. The font definition includes available axes of variation. Something else we can ignore for now. PsychSetATSUStyleAttributesFromPsychWindowRecord(atsuStyle, winRec); //don't bother to set the variations of the style. //don't bother to set the features of the style. //associate the style with our layout object. This call assigns a style to every character of the string to be displayed. callError=ATSUSetRunStyle(textLayout, atsuStyle, (UniCharArrayOffset)0, (UniCharCount)stringLengthChars); // Define the meaning of the y position of the specified drawing cursor. // We get the global setting from the Screen preference, but allow to override // it on a per-invocation basis via the optional 7th argument to 'DrawText': yPositionIsBaseline = PsychPrefStateGet_TextYPositionIsBaseline(); PsychCopyInIntegerArg(5, kPsychArgOptional, &yPositionIsBaseline); if (yPositionIsBaseline) { // Y position of drawing cursor defines distance between top of text and // baseline of text, i.e. the textheight excluding descenders of letters: // Need to compute offset via ATSU: ATSUTextMeasurement mleft, mright, mtop, mbottom; callError=ATSUGetUnjustifiedBounds(textLayout, kATSUFromTextBeginning, kATSUToTextEnd, &mleft, &mright, &mbottom, &mtop); if (callError) { PsychErrorExitMsg(PsychError_internal, "Failed to compute unjustified text height to baseline in call to ATSUGetUnjustifiedBounds().\n"); } // Only take height including ascenders into account, not the descenders. // MK: Honestly, i have no clue why this is the correct calculation (or if it is // the correct calculation), but visually it seems to provide the correct results // and i'm not a typographic expert and don't intend to become one... textHeightToBaseline = fabs(Fix2X(mbottom)); } else { // Y position of drawing cursor defines top of text, therefore no offset (==0) needed: textHeightToBaseline = 0; } //Get the bounds for our text so that and create a texture of sufficient size to containt it. ATSTrapezoid trapezoid; ItemCount oActualNumberOfBounds = 0; callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 0, NULL, &oActualNumberOfBounds); if (callError || oActualNumberOfBounds!=1) { PsychErrorExitMsg(PsychError_internal, "Failed to compute bounding box in call 1 to ATSUGetGlyphBounds() (nrbounds!=1)\n"); } callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &trapezoid, &oActualNumberOfBounds); if (callError || oActualNumberOfBounds!=1) { PsychErrorExitMsg(PsychError_internal, "Failed to retrieve bounding box in call 2 to ATSUGetGlyphBounds() (nrbounds!=1)\n"); } resultPsychRect[kPsychLeft]=(Fix2X(trapezoid.upperLeft.x) < Fix2X(trapezoid.lowerLeft.x)) ? Fix2X(trapezoid.upperLeft.x) : Fix2X(trapezoid.lowerLeft.x); resultPsychRect[kPsychRight]=(Fix2X(trapezoid.upperRight.x) > Fix2X(trapezoid.lowerRight.x)) ? Fix2X(trapezoid.upperRight.x) : Fix2X(trapezoid.lowerRight.x); resultPsychRect[kPsychTop]=(Fix2X(trapezoid.upperLeft.y) < Fix2X(trapezoid.upperRight.y)) ? Fix2X(trapezoid.upperLeft.y) : Fix2X(trapezoid.upperRight.y); resultPsychRect[kPsychBottom]=(Fix2X(trapezoid.lowerLeft.y) > Fix2X(trapezoid.lowerRight.y)) ? Fix2X(trapezoid.lowerLeft.y) : Fix2X(trapezoid.lowerRight.y); PsychNormalizeRect(resultPsychRect, resultPsychNormRect); resultPsychRect[kPsychLeft]=resultPsychNormRect[kPsychLeft] + winRec->textAttributes.textPositionX; resultPsychRect[kPsychRight]=resultPsychNormRect[kPsychRight] + winRec->textAttributes.textPositionX; resultPsychRect[kPsychTop]=resultPsychNormRect[kPsychTop] + winRec->textAttributes.textPositionY - textHeightToBaseline; resultPsychRect[kPsychBottom]=resultPsychNormRect[kPsychBottom] + winRec->textAttributes.textPositionY - textHeightToBaseline; PsychCopyOutRectArg(1, FALSE, resultPsychNormRect); PsychCopyOutRectArg(2, FALSE, resultPsychRect); //release resources free((void*)textUniString); callError=ATSUDisposeStyle(atsuStyle); return(PsychError_none); }
PsychError SCREENTextBounds(void) { //for debugging TextEncodingBase textEncodingBase; TextEncodingVariant textEncodingVariant; TextEncodingFormat textEncodingFormat; /////// PsychWindowRecordType *winRec; char *textCString; Str255 textPString; UniChar *textUniString; OSStatus callError; PsychRectType resultPsychRect, resultPsychNormRect; ATSUTextLayout textLayout; //layout is a pointer to an opaque struct. int stringLengthChars; int uniCharBufferLengthElements, uniCharBufferLengthChars, uniCharBufferLengthBytes; ByteCount uniCharStringLengthBytes; TextToUnicodeInfo textToUnicodeInfo; TextEncoding textEncoding; ATSUStyle atsuStyle; Boolean foundFont; //for ATSU style attributes PsychFontStructPtrType psychFontRecord; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; //check for correct the number of arguments before getting involved PsychErrorExit(PsychCapNumInputArgs(2)); PsychErrorExit(PsychRequireNumInputArgs(2)); PsychErrorExit(PsychCapNumOutputArgs(2)); //get the window pointer and the text string and check that the window record has a font set PsychAllocInWindowRecordArg(1, kPsychArgRequired, &winRec); foundFont=PsychGetFontRecordFromFontNumber(winRec->textAttributes.textFontNumber, &psychFontRecord); if(!foundFont) PsychErrorExitMsg(PsychError_user, "Attempt to determine the bounds of text with no font or invalid font number"); //it would be better to both prevent the user from setting invalid font numbers and init to the OS 9 default font. //read in the string and get its length and convert it to a unicode string. PsychAllocInCharArg(2, kPsychArgRequired, &textCString); stringLengthChars=strlen(textCString); if(stringLengthChars > 255) PsychErrorExitMsg(PsychError_unimplemented, "Cut corners and TextBounds will not accept a string longer than 255 characters"); CopyCStringToPascal(textCString, textPString); uniCharBufferLengthChars= stringLengthChars * CHAR_TO_UNICODE_LENGTH_FACTOR; uniCharBufferLengthElements= uniCharBufferLengthChars + 1; uniCharBufferLengthBytes= sizeof(UniChar) * uniCharBufferLengthElements; textUniString=(UniChar*)malloc(uniCharBufferLengthBytes); //Using a TextEncoding type describe the encoding of the text to be converteed. textEncoding=CreateTextEncoding(kTextEncodingMacRoman, kMacRomanDefaultVariant, kTextEncodingDefaultFormat); //Take apart the encoding we just made to check it: textEncodingBase=GetTextEncodingBase(textEncoding); textEncodingVariant=GetTextEncodingVariant(textEncoding); textEncodingFormat=GetTextEncodingFormat(textEncoding); //Create a structure holding conversion information from the text encoding type we just created. callError=CreateTextToUnicodeInfoByEncoding(textEncoding,&textToUnicodeInfo); //Convert the text to a unicode string callError=ConvertFromPStringToUnicode(textToUnicodeInfo, textPString, (ByteCount)uniCharBufferLengthBytes, &uniCharStringLengthBytes, textUniString); //create the text layout object callError=ATSUCreateTextLayout(&textLayout); //associate our unicode text string with the text layout object callError=ATSUSetTextPointerLocation(textLayout, textUniString, kATSUFromTextBeginning, kATSUToTextEnd, (UniCharCount)stringLengthChars); //create an ATSU style object callError=ATSUCreateStyle(&atsuStyle); callError=ATSUClearStyle(atsuStyle); //Not that we have a style object we have to set style charactersitics. These include but are more general than Font Manager styles. //ATSU Style objects have three sets of characteristics: attributes, variations, and features. //attributes are things we need to set to match OS 9 behavior, such as the font ID, size, boldness, and italicization. //features are esoteric settings which we don't need for reproducing OS 9 behavior. Whatever clearstyle sets should be fine. //font variations are axes of variation through the space of font characteristics. The font definition includes available axes of variation. Something else we can ignore for now. PsychSetATSUStyleAttributesFromPsychWindowRecord(atsuStyle, winRec); //don't bother to set the variations of the style. //don't bother to set the features of the style. //associate the style with our layout object. This call assigns a style to every character of the string to be displayed. callError=ATSUSetRunStyle(textLayout, atsuStyle, (UniCharArrayOffset)0, (UniCharCount)stringLengthChars); //Get the bounds for our text so that and create a texture of sufficient size to containt it. ATSTrapezoid trapezoid; ItemCount oActualNumberOfBounds = 0; callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 0, NULL, &oActualNumberOfBounds); if (callError || oActualNumberOfBounds!=1) { PsychErrorExitMsg(PsychError_internal, "Failed to compute bounding box in call 1 to ATSUGetGlyphBounds() (nrbounds!=1)\n"); } callError=ATSUGetGlyphBounds(textLayout, 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &trapezoid, &oActualNumberOfBounds); if (callError || oActualNumberOfBounds!=1) { PsychErrorExitMsg(PsychError_internal, "Failed to retrieve bounding box in call 2 to ATSUGetGlyphBounds() (nrbounds!=1)\n"); } resultPsychRect[kPsychLeft]=(Fix2X(trapezoid.upperLeft.x) < Fix2X(trapezoid.lowerLeft.x)) ? Fix2X(trapezoid.upperLeft.x) : Fix2X(trapezoid.lowerLeft.x); resultPsychRect[kPsychRight]=(Fix2X(trapezoid.upperRight.x) > Fix2X(trapezoid.lowerRight.x)) ? Fix2X(trapezoid.upperRight.x) : Fix2X(trapezoid.lowerRight.x); resultPsychRect[kPsychTop]=(Fix2X(trapezoid.upperLeft.y) < Fix2X(trapezoid.upperRight.y)) ? Fix2X(trapezoid.upperLeft.y) : Fix2X(trapezoid.upperRight.y); resultPsychRect[kPsychBottom]=(Fix2X(trapezoid.lowerLeft.y) > Fix2X(trapezoid.lowerRight.y)) ? Fix2X(trapezoid.lowerLeft.y) : Fix2X(trapezoid.lowerRight.y); PsychNormalizeRect(resultPsychRect, resultPsychNormRect); PsychCopyOutRectArg(1, FALSE, resultPsychNormRect); PsychCopyOutRectArg(2, FALSE, resultPsychRect); //release resources free((void*)textUniString); callError=ATSUDisposeStyle(atsuStyle); return(PsychError_none); }