notepad-plus-plus/scintilla/cocoa/QuartzTextLayout.h

142 lines
4.7 KiB
C++

/*
* QuartzTextLayout.h
*
* Original Code by Evan Jones on Wed Oct 02 2002.
* Contributors:
* Shane Caraveo, ActiveState
* Bernd Paradies, Adobe
*
*/
#ifndef _QUARTZ_TEXT_LAYOUT_H
#define _QUARTZ_TEXT_LAYOUT_H
#include <Cocoa/Cocoa.h>
#include "QuartzTextStyle.h"
class QuartzTextLayout
{
public:
/** Create a text layout for drawing on the specified context. */
QuartzTextLayout( CGContextRef context ) : layout( NULL ), unicode_string( NULL ), unicode_length( 0 )
{
OSStatus err = ATSUCreateTextLayout( &layout );
if (0 != err)
layout = NULL;
setContext(context);
ATSUAttributeTag tag = kATSULineLayoutOptionsTag;
ByteCount size = sizeof( ATSLineLayoutOptions );
ATSLineLayoutOptions rendering = kATSLineUseDeviceMetrics; //| kATSLineFractDisable | kATSLineUseQDRendering
ATSUAttributeValuePtr valuePtr = &rendering;
err = ATSUSetLayoutControls( layout, 1, &tag, &size, &valuePtr );
}
~QuartzTextLayout()
{
if (NULL != layout)
ATSUDisposeTextLayout( layout );
layout = NULL;
if ( unicode_string != NULL )
{
delete[] unicode_string;
unicode_string = NULL;
unicode_length = 0;
}
}
/** Assign a string to the text layout object. */
// TODO: Create a UTF8 version
// TODO: Optimise the ASCII version by not copying so much
OSStatus setText( const UInt8* buffer, size_t byteLength, CFStringEncoding encoding )
{
if (NULL == layout)
return -1;
CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, encoding, false );
if (!str)
return -1;
unicode_length = CFStringGetLength( str );
if (unicode_string)
delete[] unicode_string;
unicode_string = new UniChar[ unicode_length ];
CFStringGetCharacters( str, CFRangeMake( 0, unicode_length ), unicode_string );
CFRelease( str );
str = NULL;
OSStatus err;
err = ATSUSetTextPointerLocation( layout, unicode_string, kATSUFromTextBeginning, kATSUToTextEnd, unicode_length );
if( err != noErr ) return err;
// Turn on the default font fallbacks
return ATSUSetTransientFontMatching( layout, true );
}
inline void setText( const UInt8* buffer, size_t byteLength, const QuartzTextStyle& r )
{
this->setText( buffer, byteLength, kCFStringEncodingUTF8 );
ATSUSetRunStyle( layout, r.getATSUStyle(), 0, unicode_length );
}
/** Apply the specified text style on the entire range of text. */
void setStyle( const QuartzTextStyle& style )
{
ATSUSetRunStyle( layout, style.getATSUStyle(), kATSUFromTextBeginning, kATSUToTextEnd );
}
/** Draw the text layout into the current CGContext at the specified position, flipping the CGContext's Y axis if required.
* @param x The x axis position to draw the baseline in the current CGContext.
* @param y The y axis position to draw the baseline in the current CGContext.
* @param flipTextYAxis If true, the CGContext's Y axis will be flipped before drawing the text, and restored afterwards. Use this when drawing in an HIView's CGContext, where the origin is the top left corner. */
void draw( float x, float y, bool flipTextYAxis = false )
{
if (NULL == layout || 0 == unicode_length)
return;
if ( flipTextYAxis )
{
CGContextSaveGState( gc );
CGContextScaleCTM( gc, 1.0, -1.0 );
y = -y;
}
OSStatus err;
err = ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix( x ), X2Fix( y ) );
if ( flipTextYAxis ) CGContextRestoreGState( gc );
}
/** Sets a single text layout control on the ATSUTextLayout object.
* @param tag The control to set.
* @param size The size of the parameter pointed to by value.
* @param value A pointer to the new value for the control.
*/
void setControl( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value )
{
ATSUSetLayoutControls( layout, 1, &tag, &size, &value );
}
ATSUTextLayout getLayout() {
return layout;
}
inline CFIndex getLength() const { return unicode_length; }
inline void setContext (CGContextRef context)
{
gc = context;
if (NULL != layout)
setControl( kATSUCGContextTag, sizeof( gc ), &gc );
}
private:
ATSUTextLayout layout;
UniChar* unicode_string;
int unicode_length;
CGContextRef gc;
};
#endif