~wxMacCoreGraphicsBrushData ();
virtual void Apply( wxGraphicsContext* context );
- void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
- const wxColour&c1, const wxColour&c2 );
- void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
- const wxColour &oColor, const wxColour &cColor );
+ void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+ wxDouble x2, wxDouble y2,
+ const wxGraphicsGradientStops& stops);
+ void CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+ wxDouble xc, wxDouble yc, wxDouble radius,
+ const wxGraphicsGradientStops& stops);
virtual bool IsShading() { return m_isShading; }
CGShadingRef GetShading() { return m_shading; }
protected:
- CGFunctionRef CreateGradientFunction( const wxColour& c1, const wxColour& c2 );
+ CGFunctionRef CreateGradientFunction(const wxGraphicsGradientStops& stops);
+
static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out);
virtual void Init();
bool m_isShading;
CGFunctionRef m_gradientFunction;
CGShadingRef m_shading;
- CGFloat *m_gradientComponents;
+
+ // information about a single gradient component
+ struct GradientComponent
+ {
+ CGFloat pos;
+ CGFloat red;
+ CGFloat green;
+ CGFloat blue;
+ CGFloat alpha;
+ };
+
+ // and information about all of them
+ struct GradientComponents
+ {
+ GradientComponents()
+ {
+ count = 0;
+ comps = NULL;
+ }
+
+ void Init(unsigned count_)
+ {
+ count = count_;
+ comps = new GradientComponent[count];
+ }
+
+ ~GradientComponents()
+ {
+ delete [] comps;
+ }
+
+ unsigned count;
+ GradientComponent *comps;
+ };
+
+ GradientComponents m_gradientComponents;
};
wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer )
Init();
}
-void wxMacCoreGraphicsBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
- const wxColour&c1, const wxColour&c2 )
+void
+wxMacCoreGraphicsBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+ wxDouble x2, wxDouble y2,
+ const wxGraphicsGradientStops& stops)
{
- m_gradientFunction = CreateGradientFunction( c1, c2 );
+ m_gradientFunction = CreateGradientFunction(stops);
m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) x1, (CGFloat) y1),
CGPointMake((CGFloat) x2,(CGFloat) y2), m_gradientFunction, true, true ) ;
m_isShading = true ;
}
-void wxMacCoreGraphicsBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
- const wxColour &oColor, const wxColour &cColor )
+void
+wxMacCoreGraphicsBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+ wxDouble xc, wxDouble yc,
+ wxDouble radius,
+ const wxGraphicsGradientStops& stops)
{
- m_gradientFunction = CreateGradientFunction( oColor, cColor );
+ m_gradientFunction = CreateGradientFunction(stops);
m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) xo,(CGFloat) yo), 0,
CGPointMake((CGFloat) xc,(CGFloat) yc), (CGFloat) radius, m_gradientFunction, true, true ) ;
m_isShading = true ;
if( m_gradientFunction )
CGFunctionRelease(m_gradientFunction);
-
- delete[] m_gradientComponents;
}
void wxMacCoreGraphicsBrushData::Init()
{
m_gradientFunction = NULL;
m_shading = NULL;
- m_gradientComponents = NULL;
m_isShading = false;
}
void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)
{
- CGFloat* colors = (CGFloat*) info ;
+ const GradientComponents& stops = *(GradientComponents*) info ;
+
CGFloat f = *in;
- for( int i = 0 ; i < 4 ; ++i )
+ if (f <= 0.0)
+ {
+ // Start
+ out[0] = stops.comps[0].red;
+ out[1] = stops.comps[1].green;
+ out[2] = stops.comps[2].blue;
+ out[3] = stops.comps[3].alpha;
+ }
+ else if (f >= 1.0)
+ {
+ // end
+ out[0] = stops.comps[stops.count - 1].red;
+ out[1] = stops.comps[stops.count - 1].green;
+ out[2] = stops.comps[stops.count - 1].blue;
+ out[3] = stops.comps[stops.count - 1].alpha;
+ }
+ else
{
- out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f;
+ // Find first component with position greater than f
+ unsigned i;
+ for ( i = 0; i < stops.count; i++ )
+ {
+ if (stops.comps[i].pos > f)
+ break;
+ }
+
+ // Interpolated between stops
+ CGFloat diff = (f - stops.comps[i-1].pos);
+ CGFloat range = (stops.comps[i].pos - stops.comps[i-1].pos);
+ CGFloat fact = diff / range;
+
+ out[0] = stops.comps[i - 1].red + (stops.comps[i].red - stops.comps[i - 1].red) * fact;
+ out[1] = stops.comps[i - 1].green + (stops.comps[i].green - stops.comps[i - 1].green) * fact;
+ out[2] = stops.comps[i - 1].blue + (stops.comps[i].blue - stops.comps[i - 1].blue) * fact;
+ out[3] = stops.comps[i - 1].alpha + (stops.comps[i].alpha - stops.comps[i - 1].alpha) * fact;
}
}
-CGFunctionRef wxMacCoreGraphicsBrushData::CreateGradientFunction( const wxColour& c1, const wxColour& c2 )
+CGFunctionRef
+wxMacCoreGraphicsBrushData::CreateGradientFunction(const wxGraphicsGradientStops& stops)
{
+
static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL };
static const CGFloat input_value_range [2] = { 0, 1 };
static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
- m_gradientComponents = new CGFloat[8] ;
- m_gradientComponents[0] = (CGFloat) (c1.Red() / 255.0);
- m_gradientComponents[1] = (CGFloat) (c1.Green() / 255.0);
- m_gradientComponents[2] = (CGFloat) (c1.Blue() / 255.0);
- m_gradientComponents[3] = (CGFloat) (c1.Alpha() / 255.0);
- m_gradientComponents[4] = (CGFloat) (c2.Red() / 255.0);
- m_gradientComponents[5] = (CGFloat) (c2.Green() / 255.0);
- m_gradientComponents[6] = (CGFloat) (c2.Blue() / 255.0);
- m_gradientComponents[7] = (CGFloat) (c2.Alpha() / 255.0);
-
- return CGFunctionCreate ( m_gradientComponents, 1,
+
+ m_gradientComponents.Init(stops.GetCount());
+ for ( unsigned i = 0; i < m_gradientComponents.count; i++ )
+ {
+ const wxGraphicsGradientStop stop = stops.Item(i);
+
+ m_gradientComponents.comps[i].pos = stop.GetPosition();
+
+ const wxColour col = stop.GetColour();
+ m_gradientComponents.comps[i].red = (CGFloat) (col.Red() / 255.0);
+ m_gradientComponents.comps[i].green = (CGFloat) (col.Green() / 255.0);
+ m_gradientComponents.comps[i].blue = (CGFloat) (col.Blue() / 255.0);
+ m_gradientComponents.comps[i].alpha = (CGFloat) (col.Alpha() / 255.0);
+ }
+
+ return CGFunctionCreate ( &m_gradientComponents, 1,
input_value_range,
4,
output_value_ranges,
// concatenates the matrix
void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t )
{
- m_matrix = CGAffineTransformConcat(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()) );
+ m_matrix = CGAffineTransformConcat(*((CGAffineTransform*) t->GetNativeMatrix()), m_matrix );
}
// sets the matrix to the respective values
// appends a rectangle as a new closed subpath
virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
- // appends an ellipsis as a new closed subpath fitting the passed rectangle
+ // appends a circle as a new closed subpath
virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r );
+ // appends an ellipsis as a new closed subpath fitting the passed rectangle
+ virtual void AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h);
+
// draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
void wxMacCoreGraphicsPathData::AddCircle( wxDouble x, wxDouble y , wxDouble r )
{
- CGPathAddArc( m_path , NULL , (CGFloat) x , (CGFloat) y , (CGFloat) r , (CGFloat) 0.0 , (CGFloat) (2 * M_PI) , true );
+ CGPathAddEllipseInRect( m_path, NULL, CGRectMake(x-r,y-r,2*r,2*r));
+}
+
+void wxMacCoreGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
+{
+ CGPathAddEllipseInRect( m_path, NULL, CGRectMake(x,y,w,h));
}
// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
m_cg = cg;
m_offset = offset;
if ( m_offset )
- CGContextTranslateCTM( m_cg, (CGFloat) 0.5, (CGFloat) 0.5 );
+ {
+ m_userOffset = CGContextConvertSizeToUserSpace( m_cg, CGSizeMake( 0.5 , 0.5 ) );
+ CGContextTranslateCTM( m_cg, m_userOffset.width , m_userOffset.height );
+ }
+ else
+ {
+ m_userOffset = CGSizeMake(0.0, 0.0);
+ }
+
}
~wxQuartzOffsetHelper( )
{
if ( m_offset )
- CGContextTranslateCTM( m_cg, (CGFloat) -0.5, (CGFloat) -0.5 );
+ CGContextTranslateCTM( m_cg, -m_userOffset.width , -m_userOffset.height );
}
public :
+ CGSize m_userOffset;
CGContextRef m_cg;
bool m_offset;
} ;
CGContextRestoreGState( m_cgContext );
if ( m_contextSynthesized )
{
- // TODO: in case of performance problems, try issuing this not too
- // frequently (half of refresh rate)
- CGContextFlush(m_cgContext);
#if wxOSX_USE_CARBON
QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
#endif
wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
- double w;
+ // round the returned extent: this is probably more correct anyhow but
+ // we also need to do it to be consistent with GetPartialTextExtents()
+ // below and avoid strange situation when the last partial extent
+ // returned by it could have been greater than the full extent returned
+ // by us
CGFloat a, d, l;
-
- w = CTLineGetTypographicBounds(line, &a, &d, &l) ;
+ int w = CTLineGetTypographicBounds(line, &a, &d, &l) + 0.5;
if ( height )
*height = a+d+l;
int chars = text.length();
for ( int pos = 0; pos < (int)chars; pos ++ )
{
- widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL )+0.5;
+ widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL );
}
return;
if ( m_cgContext )
CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
else
- m_windowTransform = CGAffineTransformConcat(m_windowTransform, *(CGAffineTransform*) matrix.GetNativeMatrix());
+ m_windowTransform = CGAffineTransformConcat(*(CGAffineTransform*) matrix.GetNativeMatrix(), m_windowTransform);
}
// sets the transform of this context
virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
- // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
- virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
- const wxColour&c1, const wxColour&c2) ;
+ virtual wxGraphicsBrush
+ CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+ wxDouble x2, wxDouble y2,
+ const wxGraphicsGradientStops& stops);
- // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
- // with radius r and color cColor
- virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
- const wxColour &oColor, const wxColour &cColor) ;
+ virtual wxGraphicsBrush
+ CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+ wxDouble xc, wxDouble yc,
+ wxDouble radius,
+ const wxGraphicsGradientStops& stops);
// sets the font
virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
return wxNullGraphicsBitmap;
}
-// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
-wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
- const wxColour&c1, const wxColour&c2)
+wxGraphicsBrush
+wxMacCoreGraphicsRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+ wxDouble x2, wxDouble y2,
+ const wxGraphicsGradientStops& stops)
{
wxGraphicsBrush p;
wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
- d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
+ d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
p.SetRefData(d);
return p;
}
-// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
-// with radius r and color cColor
-wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
- const wxColour &oColor, const wxColour &cColor)
+wxGraphicsBrush
+wxMacCoreGraphicsRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+ wxDouble xc, wxDouble yc,
+ wxDouble radius,
+ const wxGraphicsGradientStops& stops)
{
wxGraphicsBrush p;
wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
- d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
+ d->CreateRadialGradientBrush(xo, yo, xc, yc, radius, stops);
p.SetRefData(d);
return p;
}