File indexing completed on 2024-04-28 05:32:20

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 "oxygentileset.h"
0009 #include "oxygencairocontext.h"
0010 #include "oxygencairoutils.h"
0011 #include "oxygencolorutils.h"
0012 
0013 #include <algorithm>
0014 #include <iostream>
0015 
0016 namespace Oxygen
0017 {
0018 
0019     //______________________________________________________________
0020     TileSet::TileSet( void ):
0021         _w1(0),
0022         _h1(0),
0023         _w3(0),
0024         _h3(0)
0025     {}
0026 
0027     //______________________________________________________________
0028     TileSet::TileSet( const Cairo::Surface& surface, int w1, int h1, int w2, int h2 ):
0029         _w1(w1), _h1(h1), _w3(0), _h3(0)
0030     {
0031 
0032         int sw(0);
0033         int sh(0);
0034         cairo_surface_get_size( surface, sw, sh );
0035 
0036         // set metrics
0037         _w3 = sw - (w1 + w2);
0038         _h3 = sh - (h1 + h2);
0039 
0040         int w = w2; while (w < 32 && w2 > 0) w += w2;
0041         int h = h2; while (h < 32 && h2 > 0) h += h2;
0042 
0043         // initialise pixmap array
0044         // top
0045         initSurface( _surfaces, surface, _w1, _h1, 0, 0, _w1, _h1 );
0046         initSurface( _surfaces, surface, w, _h1, _w1, 0, w2, _h1 );
0047         initSurface( _surfaces, surface, _w3, _h1, _w1+w2, 0, _w3, _h1 );
0048 
0049         // center
0050         initSurface( _surfaces, surface, _w1, h, 0, _h1, _w1, h2 );
0051         initSurface( _surfaces, surface, w, h, w1, _h1, w2, h2 );
0052         initSurface( _surfaces, surface, _w3, h, _w1+w2, _h1, _w3, h2 );
0053 
0054         // bottom
0055         initSurface( _surfaces, surface, _w1, _h3, 0, _h1+h2, _w1, _h3 );
0056         initSurface( _surfaces, surface, w, _h3, _w1, _h1+h2, w2, _h3 );
0057         initSurface( _surfaces, surface, _w3, _h3, _w1+w2, _h1+h2, _w3, _h3 );
0058 
0059         if(!isValid())
0060             std::cerr << "oxygen-gtk: BUG: created tileset looks invalid, expect resource leaks ("<<__FILE__<<":"<<__LINE__<<")\n";
0061 
0062     }
0063 
0064     //______________________________________________________________
0065     TileSet::TileSet( const Cairo::Surface& surface, int w1, int h1, int w3, int h3, int x1, int y1, int w2, int h2):
0066         _w1(w1), _h1(h1), _w3(w3), _h3(h3)
0067     {
0068 
0069         int sw(0);
0070         int sh(0);
0071         cairo_surface_get_size( surface, sw, sh );
0072 
0073         // set metrics
0074         int x2 = sw - _w3;
0075         int y2 = sh - _h3;
0076         int w = w2; while (w < 32 && w2 > 0) w += w2;
0077         int h = h2; while (h < 32 && h2 > 0) h += h2;
0078 
0079         // initialise surface array
0080         // top
0081         initSurface( _surfaces, surface, _w1, _h1, 0, 0, _w1, _h1 );
0082         initSurface( _surfaces, surface, w, _h1, x1, 0, w2, _h1 );
0083         initSurface( _surfaces, surface, _w3, h1, x2, 0, _w3, _h1 );
0084 
0085         // center
0086         initSurface( _surfaces, surface, _w1, h, 0, y1, _w1, h2 );
0087         initSurface( _surfaces, surface, w, h, x1, y1, w2, h2 );
0088         initSurface( _surfaces, surface, _w3, h, x2, y1, _w3, h2 );
0089 
0090         // bottom
0091         initSurface( _surfaces, surface, _w1, _h3, 0, y2, _w1, _h3 );
0092         initSurface( _surfaces, surface, w, _h3, x1, y2, w2, _h3 );
0093         initSurface( _surfaces, surface, _w3, _h3, x2, y2, _w3, _h3 );
0094 
0095     }
0096 
0097     //______________________________________________________________
0098     TileSet::~TileSet( void )
0099     {}
0100 
0101     //___________________________________________________________
0102     inline bool bits( unsigned int flags, unsigned int testFlags)
0103     { return (flags & testFlags) == testFlags; }
0104 
0105     //______________________________________________________________
0106     void TileSet::render( cairo_t* context, int x0, int y0, int w, int h, unsigned int t ) const
0107     {
0108 
0109         // check initialization
0110         if( _surfaces.size() < 9 ) return;
0111 
0112         // calculate pixmaps widths
0113         int wLeft(0);
0114         int wRight(0);
0115         if( _w1+_w3 > 0 )
0116         {
0117             double wRatio( double( _w1 )/double( _w1 + _w3 ) );
0118             wLeft = (t&Right) ? std::min( _w1, int(w*wRatio) ):_w1;
0119             wRight = (t&Left) ? std::min( _w3, int(w*(1.0-wRatio)) ):_w3;
0120         }
0121 
0122         // calculate pixmap heights
0123         int hTop(0);
0124         int hBottom(0);
0125         if( _h1+_h3 > 0 )
0126         {
0127             double hRatio( double( _h1 )/double( _h1 + _h3 ) );
0128             hTop = (t&Bottom) ? std::min( _h1, int(h*hRatio) ):_h1;
0129             hBottom = (t&Top) ? std::min( _h3, int(h*(1.0-hRatio)) ):_h3;
0130         }
0131 
0132         // calculate corner locations
0133         w -= wLeft + wRight;
0134         h -= hTop + hBottom;
0135         int x1 = x0 + wLeft;
0136         int x2 = x1 + w;
0137         int y1 = y0 + hTop;
0138         int y2 = y1 + h;
0139 
0140         // corners
0141         if( bits(t, Top|Left) )  copySurface( context, x0, y0, _surfaces.at(0), 0, 0, wLeft, hTop, CAIRO_EXTEND_NONE );
0142         if( bits(t, Top|Right) ) copySurface( context, x2, y0, _surfaces.at(2), _w3-wRight, 0, wRight, hTop, CAIRO_EXTEND_NONE);
0143         if( bits(t, Bottom|Left) )  copySurface( context, x0, y2, _surfaces.at(6), 0, _h3-hBottom, wLeft, hBottom, CAIRO_EXTEND_NONE);
0144         if( bits(t, Bottom|Right) ) copySurface( context, x2, y2, _surfaces.at(8), _w3-wRight, _h3-hBottom, wRight, hBottom, CAIRO_EXTEND_NONE );
0145 
0146         // top and bottom
0147         if( w > 0 )
0148         {
0149             if( t & Top ) copySurface( context, x1, y0, _surfaces.at(1), 0, 0, w, hTop, CAIRO_EXTEND_REPEAT );
0150             if( t & Bottom ) copySurface( context, x1, y2, _surfaces.at(7), 0, _h3-hBottom, w, hBottom, CAIRO_EXTEND_REPEAT );
0151         }
0152 
0153         // left and right
0154         if( h > 0 )
0155         {
0156             if( t & Left ) copySurface( context, x0, y1, _surfaces.at(3), 0, 0, wLeft, h, CAIRO_EXTEND_REPEAT );
0157             if( t & Right ) copySurface( context, x2, y1, _surfaces.at(5), _w3-wRight, 0, wRight, h, CAIRO_EXTEND_REPEAT );
0158         }
0159 
0160         // center
0161         if ( (t & Center) && h > 0 && w > 0 ) copySurface( context, x1, y1, _surfaces.at(4), 0, 0, w, h, CAIRO_EXTEND_REPEAT );
0162 
0163     }
0164 
0165     //______________________________________________________________
0166     void TileSet::initSurface( SurfaceList& surfaces, const Cairo::Surface &source, int w, int h, int sx, int sy, int sw, int sh )
0167     {
0168 
0169         if( sw <= 0 || sh<= 0 || w <=0 || h <= 0 ) surfaces.push_back( 0L );
0170         else {
0171 
0172             // create new surface
0173             Cairo::Surface dest( cairo_surface_create_similar( source, CAIRO_CONTENT_COLOR_ALPHA, w, h ) );
0174             Cairo::Context context( dest );
0175 
0176             if( sw == w && sh == h ) {
0177 
0178                 cairo_set_source_surface( context, source, -sx, -sy );
0179                 cairo_rectangle( context, 0, 0, w, h );
0180                 cairo_fill( context );
0181 
0182             } else {
0183 
0184                 // Bug 316066
0185                 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 4)
0186                 Cairo::Surface tile( cairo_surface_create_for_rectangle( source, sx, sy, sw, sh ) );
0187                 #else
0188                 Cairo::Surface tile( cairo_surface_create_similar( source, CAIRO_CONTENT_COLOR_ALPHA, sw, sh ) );
0189                 {
0190                     Cairo::Context local( tile );
0191                     cairo_set_source_surface( local, source, -sx, -sy );
0192                     cairo_rectangle( local, 0, 0, sw, sh );
0193                     cairo_fill( local );
0194                 }
0195                 #endif
0196 
0197                 cairo_set_source_surface( context, tile, 0, 0 );
0198                 cairo_pattern_set_extend( cairo_get_source( context ), CAIRO_EXTEND_REPEAT );
0199                 cairo_rectangle( context, 0, 0, w, h );
0200                 cairo_fill( context );
0201 
0202             }
0203 
0204             surfaces.push_back( dest );
0205 
0206         }
0207     }
0208 
0209     //______________________________________________________________
0210     void TileSet::copySurface( cairo_t* context, int x, int y, const Cairo::Surface& source, int sx, int sy, int sw, int sh, cairo_extend_t extend ) const
0211     {
0212 
0213         if( !source ) return;
0214         cairo_translate( context, x, y );
0215         cairo_rectangle( context, 0, 0, sw, sh );
0216 
0217         cairo_set_source_surface( context, source, -sx, -sy );
0218         cairo_pattern_set_extend( cairo_get_source( context ), extend );
0219         cairo_fill( context );
0220         cairo_translate( context, -x, -y );
0221     }
0222 
0223 }