1 /* 2 * QuartzTextLayout.h 3 * 4 * Original Code by Evan Jones on Wed Oct 02 2002. 5 * Contributors: 6 * Shane Caraveo, ActiveState 7 * Bernd Paradies, Adobe 8 * 9 */ 10 11 #ifndef QUARTZTEXTLAYOUT_H 12 #define QUARTZTEXTLAYOUT_H 13 14 #include <Cocoa/Cocoa.h> 15 16 #include "QuartzTextStyle.h" 17 18 19 class QuartzTextLayout { 20 public: 21 /** Create a text layout for drawing. */ QuartzTextLayout()22 QuartzTextLayout() : mString(NULL), mLine(NULL), stringLength(0) { 23 } 24 ~QuartzTextLayout()25 ~QuartzTextLayout() { 26 if (mString) { 27 CFRelease(mString); 28 mString = NULL; 29 } 30 if (mLine) { 31 CFRelease(mLine); 32 mLine = NULL; 33 } 34 } 35 setText(std::string_view sv,CFStringEncoding encoding,const QuartzTextStyle & r)36 CFStringEncoding setText(std::string_view sv, CFStringEncoding encoding, const QuartzTextStyle &r) { 37 // First clear current values in case of failure. 38 if (mString) { 39 CFRelease(mString); 40 mString = NULL; 41 } 42 if (mLine) { 43 CFRelease(mLine); 44 mLine = NULL; 45 } 46 47 const UInt8 *puiBuffer = reinterpret_cast<const UInt8 *>(sv.data()); 48 CFStringRef str = CFStringCreateWithBytes(NULL, puiBuffer, sv.length(), encoding, false); 49 if (!str) { 50 // Failed to decode bytes into string with given encoding so try 51 // MacRoman which should accept any byte. 52 encoding = kCFStringEncodingMacRoman; 53 str = CFStringCreateWithBytes(NULL, puiBuffer, sv.length(), encoding, false); 54 } 55 if (!str) { 56 return encoding; 57 } 58 59 stringLength = CFStringGetLength(str); 60 61 CFMutableDictionaryRef stringAttribs = r.getCTStyle(); 62 63 mString = ::CFAttributedStringCreate(NULL, str, stringAttribs); 64 65 mLine = ::CTLineCreateWithAttributedString(mString); 66 67 CFRelease(str); 68 return encoding; 69 } 70 71 /** Draw the text layout into a CGContext at the specified position. 72 * @param gc The CGContext in which to draw the text. 73 * @param x The x axis position to draw the baseline in the current CGContext. 74 * @param y The y axis position to draw the baseline in the current CGContext. */ draw(CGContextRef gc,float x,float y)75 void draw(CGContextRef gc, float x, float y) { 76 if (!mLine) 77 return; 78 79 ::CGContextSetTextMatrix(gc, CGAffineTransformMakeScale(1.0, -1.0)); 80 81 // Set the text drawing position. 82 ::CGContextSetTextPosition(gc, x, y); 83 84 // And finally, draw! 85 ::CTLineDraw(mLine, gc); 86 } 87 MeasureStringWidth()88 float MeasureStringWidth() { 89 if (mLine == NULL) 90 return 0.0f; 91 92 return static_cast<float>(::CTLineGetTypographicBounds(mLine, NULL, NULL, NULL)); 93 } 94 getCTLine()95 CTLineRef getCTLine() { 96 return mLine; 97 } 98 getStringLength()99 CFIndex getStringLength() { 100 return stringLength; 101 } 102 103 private: 104 CFAttributedStringRef mString; 105 CTLineRef mLine; 106 CFIndex stringLength; 107 }; 108 109 #endif 110