File indexing completed on 2024-04-28 05:32:10
0001 /* 0002 this file is part of the oxygen gtk engine 0003 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "oxygencairoutils.h" 0009 #include "oxygencairocontext.h" 0010 #include "oxygenrgba.h" 0011 0012 #ifdef GDK_WINDOWING_X11 0013 #include <cairo/cairo-xlib.h> 0014 #endif 0015 0016 #include <cmath> 0017 namespace Oxygen 0018 { 0019 0020 //__________________________________________________________________ 0021 void cairo_arc_qt(cairo_t* context, double x, double y, double diam, double a, double alen) 0022 { 0023 0024 const double xc( x+diam/2 ); 0025 const double yc( y+diam/2 ); 0026 const double radius( diam/2 ); 0027 0028 double angle1( -a ); 0029 double angle2( -(alen+a) ); 0030 0031 if( angle1 > angle2 ) std::swap( angle1, angle2 ); 0032 cairo_arc(context, xc,yc,radius,angle1,angle2); 0033 0034 } 0035 0036 //__________________________________________________________________ 0037 void cairo_pattern_add_color_stop( cairo_pattern_t* pattern, double x, const ColorUtils::Rgba& color ) 0038 { 0039 /* 0040 for some reason passing 1.0 for the upperbound on some gradients 0041 breaks the gradient definition internally with some compilers 0042 this is fixed by passing a value close to (but smaller than) unity. 0043 */ 0044 cairo_pattern_add_color_stop_rgba( pattern, x, color.red(), color.green(), color.blue(), color.alpha() ); 0045 } 0046 0047 //__________________________________________________________________ 0048 ColorStop::List cairo_pattern_get_color_stops( cairo_pattern_t* pattern ) 0049 { 0050 0051 ColorStop::List out; 0052 int count(0); 0053 if( cairo_pattern_get_color_stop_count( pattern, &count ) != CAIRO_STATUS_SUCCESS ) return out; 0054 0055 for( int i = 0; i < count; ++i ) 0056 { 0057 double x(0); 0058 double r(0), g(0), b(0), a(0); 0059 assert( cairo_pattern_get_color_stop_rgba( pattern, i, &x, &r, &g, &b, &a ) == CAIRO_STATUS_SUCCESS ); 0060 out.push_back( ColorStop( x, ColorUtils::Rgba( r, g, b, a ) ) ); 0061 } 0062 0063 return out; 0064 0065 } 0066 0067 //__________________________________________________________________ 0068 void cairo_set_source( cairo_t* context, const ColorUtils::Rgba& color ) 0069 { cairo_set_source_rgba( context, color.red(), color.green(), color.blue(), color.alpha() ); } 0070 0071 //__________________________________________________________________ 0072 void cairo_rounded_rectangle( cairo_t* context, double x, double y, double w, double h, double r, Corners corners ) 0073 { 0074 if(corners==CornersAll) 0075 { 0076 if(w<2*r) 0077 { 0078 double r0=r; 0079 r=0.5*w; 0080 y+=r0-r; 0081 h-=2*(r0-r); 0082 } 0083 if(h<2*r) 0084 { 0085 double r0=r; 0086 r=0.5*h; 0087 x+=r0-r; 0088 w-=2*(r0-r); 0089 } 0090 } 0091 0092 if( corners == CornersNone ) 0093 { 0094 cairo_rectangle( context, x, y, w, h ); 0095 return; 0096 } 0097 0098 if( corners & CornersTopLeft ) 0099 { 0100 cairo_move_to( context, x, y+r ); 0101 cairo_arc( context, x+r, y+r, r, M_PI, 3.0*M_PI/2 ); 0102 } else cairo_move_to( context, x, y ); 0103 0104 if( corners & CornersTopRight ) 0105 { 0106 cairo_line_to( context, x+w-r, y ); 0107 cairo_arc( context, x+w-r, y+r, r, -M_PI/2, 0 ); 0108 } else cairo_line_to( context, x+w, y ); 0109 0110 if( corners & CornersBottomRight ) 0111 { 0112 cairo_line_to( context, x+w, y+h-r ); 0113 cairo_arc( context, x+w-r, y+h-r, r, 0, M_PI/2 ); 0114 } else cairo_line_to( context, x+w, y+h ); 0115 0116 if( corners & CornersBottomLeft ) 0117 { 0118 cairo_line_to( context, x+r, y+h ); 0119 cairo_arc( context, x+r, y+h-r, r, M_PI/2, M_PI ); 0120 } else cairo_line_to( context, x, y+h ); 0121 0122 cairo_close_path( context ); 0123 0124 } 0125 0126 //__________________________________________________________________ 0127 void cairo_rounded_rectangle_negative( cairo_t* context, double x, double y, double w, double h, double r, Corners corners ) 0128 { 0129 0130 if( corners == CornersNone ) 0131 { 0132 cairo_rectangle_negative( context, x, y, w, h ); 0133 return; 0134 } 0135 0136 if( corners & CornersTopRight ) 0137 { 0138 cairo_move_to( context, x+w, y+r ); 0139 cairo_arc_negative( context, x+w-r, y+r, r, 0, -M_PI/2 ); 0140 } else cairo_move_to( context, x+w, y ); 0141 0142 if( corners & CornersTopLeft ) 0143 { 0144 cairo_line_to( context, x+r, y ); 0145 cairo_arc_negative( context, x+r, y+r, r, -M_PI/2, -M_PI ); 0146 } else cairo_line_to( context, x, y ); 0147 0148 if( corners & CornersBottomLeft ) 0149 { 0150 cairo_line_to( context, x, y+h-r ); 0151 cairo_arc_negative( context, x+r, y+h-r, r, -M_PI, -3.0*M_PI/2 ); 0152 } else cairo_line_to( context, x, y+h ); 0153 0154 if( corners & CornersBottomRight ) 0155 { 0156 cairo_line_to( context, x+w-r, y+h ); 0157 cairo_arc_negative( context, x+w-r, y+h-r, r, M_PI/2, 0 ); 0158 } else cairo_line_to( context, x+w, y+h ); 0159 0160 cairo_close_path( context ); 0161 0162 } 0163 0164 //__________________________________________________________________ 0165 void cairo_rectangle_negative( cairo_t* context, double x, double y, double w, double h ) 0166 { 0167 0168 cairo_move_to( context, x+w, y ); 0169 cairo_line_to( context, x, y ); 0170 cairo_line_to( context, x, y+h ); 0171 cairo_line_to( context, x+w, y+h ); 0172 cairo_close_path( context ); 0173 0174 } 0175 0176 //__________________________________________________________________ 0177 void cairo_ellipse( cairo_t* context, double x, double y, double w, double h ) 0178 { 0179 cairo_save( context ); 0180 cairo_translate( context, x+w/2, y+h/2 ); 0181 cairo_scale( context, w/2, h/2 ); 0182 cairo_arc( context, 0, 0, 1, 0, 2.0*M_PI); 0183 cairo_restore( context ); 0184 } 0185 0186 //___________________________________________________________ 0187 void cairo_ellipse_negative( cairo_t* context, double x, double y, double w, double h ) 0188 { 0189 cairo_save( context ); 0190 cairo_translate( context, x+w/2, y+h/2 ); 0191 cairo_scale( context, w/2, h/2 ); 0192 cairo_arc_negative( context, 0, 0, 1, 2.0*M_PI, 0); 0193 cairo_restore( context ); 0194 } 0195 0196 //__________________________________________________________________ 0197 void cairo_polygon( cairo_t* context, const Polygon& polygon ) 0198 { 0199 for( Polygon::const_iterator iter = polygon.begin(); iter != polygon.end(); ++iter ) 0200 { 0201 if( iter == polygon.begin() ) cairo_move_to( context, iter->x(), iter->y() ); 0202 else cairo_line_to( context, iter->x(), iter->y() ); 0203 } 0204 } 0205 0206 //_____________________________________________________ 0207 int cairo_surface_get_width( cairo_surface_t* surface ) 0208 { 0209 const cairo_surface_type_t type( cairo_surface_get_type( surface ) ); 0210 switch( type ) 0211 { 0212 0213 case CAIRO_SURFACE_TYPE_IMAGE: 0214 return cairo_image_surface_get_width( surface ); 0215 0216 #if CAIRO_HAS_XLIB_SURFACE 0217 case CAIRO_SURFACE_TYPE_XLIB: 0218 return cairo_xlib_surface_get_width( surface ); 0219 #endif 0220 0221 default: 0222 { 0223 // This is less efficient, still makes rendering correct 0224 Cairo::Context context(surface); 0225 double x1,x2,dummy; 0226 cairo_clip_extents(context,&x1,&dummy,&x2,&dummy); 0227 return int(x2-x1); 0228 } 0229 } 0230 0231 } 0232 0233 //_____________________________________________________ 0234 int cairo_surface_get_height( cairo_surface_t* surface ) 0235 { 0236 const cairo_surface_type_t type( cairo_surface_get_type( surface ) ); 0237 switch( type ) 0238 { 0239 case CAIRO_SURFACE_TYPE_IMAGE: 0240 return cairo_image_surface_get_height( surface ); 0241 0242 #if CAIRO_HAS_XLIB_SURFACE 0243 case CAIRO_SURFACE_TYPE_XLIB: 0244 return cairo_xlib_surface_get_height( surface ); 0245 #endif 0246 0247 default: 0248 { 0249 // This is less efficient, still makes rendering correct 0250 Cairo::Context context(surface); 0251 double y1,y2,dummy; 0252 cairo_clip_extents(context,&dummy,&y1,&dummy,&y2); 0253 return int(y2-y1); 0254 } 0255 } 0256 0257 } 0258 0259 0260 //_____________________________________________________ 0261 void cairo_surface_get_size( cairo_surface_t* surface, int& width, int& height ) 0262 { 0263 0264 const cairo_surface_type_t type( cairo_surface_get_type( surface ) ); 0265 switch( type ) 0266 { 0267 case CAIRO_SURFACE_TYPE_IMAGE: 0268 width = cairo_image_surface_get_width( surface ); 0269 height = cairo_image_surface_get_height( surface ); 0270 return; 0271 0272 #if CAIRO_HAS_XLIB_SURFACE 0273 case CAIRO_SURFACE_TYPE_XLIB: 0274 width = cairo_xlib_surface_get_width( surface ); 0275 height = cairo_xlib_surface_get_height( surface ); 0276 return; 0277 #endif 0278 0279 default: 0280 { 0281 // This is less efficient, still makes rendering correct 0282 Cairo::Context context(surface); 0283 double x1, x2, y1, y2; 0284 cairo_clip_extents( context, &x1, &y1, &x2, &y2 ); 0285 width = int( x2 - x1 ); 0286 height = int( y2 - y1 ); 0287 return; 0288 } 0289 } 0290 0291 } 0292 0293 //__________________________________________________________________ 0294 cairo_surface_t* cairo_surface_copy( cairo_surface_t* source ) 0295 { 0296 0297 const int width( cairo_surface_get_width( source ) ); 0298 const int height( cairo_surface_get_height( source ) ); 0299 cairo_surface_t* dest = cairo_surface_create_similar( source, CAIRO_CONTENT_COLOR_ALPHA, width, height ); 0300 0301 // create context on surface 0302 cairo_t* context( cairo_create( dest ) ); 0303 cairo_set_source_surface( context, source, 0, 0 ); 0304 cairo_rectangle( context, 0, 0, width, height ); 0305 cairo_fill( context ); 0306 0307 cairo_destroy( context ); 0308 return dest; 0309 0310 } 0311 0312 //__________________________________________________________________ 0313 void cairo_surface_add_alpha( cairo_surface_t* surface, double alpha ) 0314 { 0315 0316 // create context on surface 0317 cairo_t* context( cairo_create( surface ) ); 0318 cairo_set_operator( context, CAIRO_OPERATOR_DEST_IN ); 0319 cairo_set_source_rgba( context, 1, 1, 1, alpha ); 0320 cairo_rectangle( context, 0, 0, cairo_surface_get_width( surface ), cairo_surface_get_height( surface ) ); 0321 cairo_fill( context ); 0322 cairo_destroy( context ); 0323 return; 0324 0325 } 0326 0327 //__________________________________________________________________ 0328 void cairo_image_surface_saturate( cairo_surface_t* surface, double saturation ) 0329 { 0330 0331 // make sure right type is used 0332 assert( cairo_surface_get_type( surface ) == CAIRO_SURFACE_TYPE_IMAGE ); 0333 assert( cairo_image_surface_get_format( surface ) == CAIRO_FORMAT_ARGB32 ); 0334 0335 0336 // dimensions and stride 0337 const int width( cairo_image_surface_get_width( surface ) ); 0338 const int height( cairo_image_surface_get_width( surface ) ); 0339 const int stride( cairo_image_surface_get_stride( surface ) ); 0340 const int bytesPerPixel(4); 0341 0342 // data 0343 unsigned char* data( cairo_image_surface_get_data( surface ) ); 0344 assert( data ); 0345 0346 int t; 0347 #define INTENSITY(r, g, b) ((unsigned char)((r) * 0.30 + (g) * 0.59 + (b) * 0.11)) 0348 #define CLAMP_UCHAR(v) (t = (v), CLAMP (t, 0, 255)) 0349 #define SATURATE(v) int(((1.0 - saturation) * intensity + saturation * (v))) 0350 0351 unsigned char* line(data); 0352 unsigned char* pixel(data); 0353 0354 for( int i = 0 ; i < height ; i++ ) 0355 { 0356 0357 pixel = line; 0358 line += stride; 0359 0360 for( int j = 0 ; j < width ; j++ ) 0361 { 0362 unsigned char intensity = INTENSITY( pixel[0], pixel[1], pixel[2] ); 0363 pixel[0] = CLAMP_UCHAR( SATURATE( pixel[0] ) ); 0364 pixel[1] = CLAMP_UCHAR( SATURATE( pixel[1] ) ); 0365 pixel[2] = CLAMP_UCHAR( SATURATE( pixel[2] ) ); 0366 pixel += bytesPerPixel; 0367 0368 } 0369 0370 } 0371 0372 } 0373 0374 }