odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

bl_bench_backend_agg.cpp (50584B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #ifdef BL_BENCH_ENABLE_AGG
      7 
      8 #include "bl_bench_app.h"
      9 #include "bl_bench_backend.h"
     10 
     11 #include <algorithm>
     12 #include <cmath>
     13 
     14 #include "agg_basics.h"
     15 #include "agg_bezier_arc.h"
     16 #include "agg_conv_curve.h"
     17 #include "agg_conv_stroke.h"
     18 #include "agg_conv_transform.h"
     19 #include "agg_font_cache_manager.h"
     20 #include "agg_gamma_functions.h"
     21 #include "agg_image_accessors.h"
     22 #include "agg_path_storage.h"
     23 #include "agg_pixfmt_rgba.h"
     24 #include "agg_rasterizer_scanline_aa.h"
     25 #include "agg_rasterizer_scanline_aa_nogamma.h"
     26 #include "agg_renderer_base.h"
     27 #include "agg_renderer_scanline.h"
     28 #include "agg_rendering_buffer.h"
     29 #include "agg_rounded_rect.h"
     30 #include "agg_scanline_u.h"
     31 #include "agg_span_allocator.h"
     32 #include "agg_span_converter.h"
     33 #include "agg_span_gradient.h"
     34 #include "agg_span_image_filter_rgba.h"
     35 #include "agg_span_interpolator_linear.h"
     36 #include "agg_trans_affine.h"
     37 #include "agg_trans_viewport.h"
     38 
     39 // AGG Benchmarking - Agg2D Abstraction
     40 // ====================================
     41 
     42 // Agg2D - Version 1.0 (with modifications)
     43 // Based on Anti-Grain Geometry
     44 // Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com)
     45 //
     46 // Permission to copy, use, modify, sell and distribute this software
     47 // is granted provided this copyright notice appears in all copies.
     48 // This software is provided "as is" without express or implied
     49 // warranty, and with no claim as to its suitability for any purpose.
     50 //
     51 // Modifications:
     52 //   25 Jan 2007 - Ported to AGG 2.4 Jerry Evans (jerry@novadsp.com)
     53 //   21 June 2023 - Modified to only provide the required API for benchmarks
     54 static const double g_approxScale = 2.0;
     55 
     56 class Agg2D {
     57   typedef agg::order_bgra ComponentOrder;
     58 
     59   typedef agg::rgba8 ColorType;
     60   typedef agg::blender_rgba_pre<ColorType, ComponentOrder> BlenderPre;
     61   typedef agg::comp_op_adaptor_rgba_pre<ColorType, ComponentOrder> BlenderCompPre;
     62 
     63   typedef agg::pixfmt_bgra32_pre PixFormatPre;
     64   typedef agg::pixfmt_custom_blend_rgba<BlenderCompPre,agg::rendering_buffer> PixFormatCompPre;
     65 
     66   typedef agg::renderer_base<PixFormatPre> RendererBasePre;
     67   typedef agg::renderer_base<PixFormatCompPre> RendererBaseCompPre;
     68 
     69   typedef agg::renderer_scanline_aa_solid<RendererBasePre> RendererSolid;
     70   typedef agg::renderer_scanline_aa_solid<RendererBaseCompPre> RendererSolidComp;
     71 
     72   typedef agg::span_allocator<ColorType> SpanAllocator;
     73   typedef agg::pod_auto_array<ColorType, 256> GradientArray;
     74 
     75   typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_x,      GradientArray> LinearGradientSpan;
     76   typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_circle, GradientArray> RadialGradientSpan;
     77   typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_conic , GradientArray> ConicGradientSpan;
     78 
     79   typedef agg::conv_curve<agg::path_storage> ConvCurve;
     80   typedef agg::conv_stroke<ConvCurve> ConvStroke;
     81   typedef agg::conv_transform<ConvCurve> PathTransform;
     82   typedef agg::conv_transform<ConvStroke> StrokeTransform;
     83 
     84   enum StyleFlag {
     85     None,
     86     Solid,
     87     Linear,
     88     Radial
     89   };
     90 
     91 public:
     92   friend class Agg2DRenderer;
     93 
     94   typedef ColorType         Color;
     95   typedef agg::rect_i       Rect;
     96   typedef agg::rect_d       RectD;
     97   typedef agg::trans_affine Affine;
     98 
     99   enum StyleSlot {
    100     FillSlot,
    101     StrokeSlot
    102   };
    103 
    104   enum LineJoin {
    105     JoinMiter = agg::miter_join,
    106     JoinRound = agg::round_join,
    107     JoinBevel = agg::bevel_join
    108   };
    109 
    110   enum LineCap {
    111     CapButt   = agg::butt_cap,
    112     CapSquare = agg::square_cap,
    113     CapRound  = agg::round_cap
    114   };
    115 
    116   enum DrawPathFlag {
    117     FillOnly,
    118     StrokeOnly,
    119     FillAndStroke,
    120     FillWithLineColor
    121   };
    122 
    123   enum ImageFilter {
    124     NoFilter,
    125     Bilinear
    126   };
    127 
    128   enum ImageResample {
    129     NoResample,
    130     ResampleAlways,
    131     ResampleOnZoomOut
    132   };
    133 
    134   enum BlendMode {
    135     BlendAlpha      = agg::end_of_comp_op_e,
    136     BlendClear      = agg::comp_op_clear,
    137     BlendSrc        = agg::comp_op_src,
    138     BlendDst        = agg::comp_op_dst,
    139     BlendSrcOver    = agg::comp_op_src_over,
    140     BlendDstOver    = agg::comp_op_dst_over,
    141     BlendSrcIn      = agg::comp_op_src_in,
    142     BlendDstIn      = agg::comp_op_dst_in,
    143     BlendSrcOut     = agg::comp_op_src_out,
    144     BlendDstOut     = agg::comp_op_dst_out,
    145     BlendSrcAtop    = agg::comp_op_src_atop,
    146     BlendDstAtop    = agg::comp_op_dst_atop,
    147     BlendXor        = agg::comp_op_xor,
    148     BlendAdd        = agg::comp_op_plus,
    149     BlendMultiply   = agg::comp_op_multiply,
    150     BlendScreen     = agg::comp_op_screen,
    151     BlendOverlay    = agg::comp_op_overlay,
    152     BlendDarken     = agg::comp_op_darken,
    153     BlendLighten    = agg::comp_op_lighten,
    154     BlendColorDodge = agg::comp_op_color_dodge,
    155     BlendColorBurn  = agg::comp_op_color_burn,
    156     BlendHardLight  = agg::comp_op_hard_light,
    157     BlendSoftLight  = agg::comp_op_soft_light,
    158     BlendDifference = agg::comp_op_difference,
    159     BlendExclusion  = agg::comp_op_exclusion
    160   };
    161 
    162   enum Direction {
    163     CW, CCW
    164   };
    165 
    166   struct Transformations {
    167     double affineMatrix[6];
    168   };
    169 
    170   struct Image {
    171     agg::rendering_buffer renBuf;
    172 
    173     Image() {}
    174     Image(unsigned char* buf, unsigned width, unsigned height, int stride) :
    175         renBuf(buf, width, height, stride) {}
    176 
    177     void attach(unsigned char* buf, unsigned width, unsigned height, int stride) {
    178       renBuf.attach(buf, width, height, stride);
    179     }
    180 
    181     int width() const { return renBuf.width(); }
    182     int height() const { return renBuf.height(); }
    183   };
    184 
    185 private:
    186   agg::rendering_buffer           m_rbuf;
    187   PixFormatPre                    m_pixFormatPre;
    188   PixFormatCompPre                m_pixFormatCompPre;
    189   RendererBasePre                 m_renBasePre;
    190   RendererBaseCompPre             m_renBaseCompPre;
    191   RendererSolid                   m_renSolid;
    192   RendererSolidComp               m_renSolidComp;
    193 
    194   SpanAllocator                   m_allocator;
    195   RectD                           m_clipBox;
    196 
    197   BlendMode                       m_blendMode;
    198   BlendMode                       m_imageBlendMode;
    199   Color                           m_imageBlendColor;
    200 
    201   agg::scanline_u8                m_scanline;
    202   agg::rasterizer_scanline_aa_nogamma<> m_rasterizer;
    203   double                          m_masterAlpha;
    204 
    205   Color                           m_color[2];
    206   GradientArray                   m_gradient[2];
    207 
    208   LineCap                         m_lineCap;
    209   LineJoin                        m_lineJoin;
    210 
    211   StyleFlag                       m_styleFlag[2];
    212   agg::trans_affine               m_gradientMatrix[2];
    213   double                          m_gradientD1[2];
    214   double                          m_gradientD2[2];
    215 
    216   ImageFilter                     m_imageFilter;
    217   ImageResample                   m_imageResample;
    218   agg::image_filter_lut           m_imageFilterLut;
    219 
    220   agg::span_interpolator_linear<> m_gradientInterpolator[2];
    221 
    222   agg::gradient_x                 m_linearGradientFunction;
    223   agg::gradient_circle            m_radialGradientFunction;
    224 
    225   double                          m_lineWidth;
    226   bool                            m_evenOddFlag;
    227 
    228   agg::path_storage               m_path;
    229   agg::trans_affine               m_transform;
    230 
    231   ConvCurve                       m_convCurve;
    232   ConvStroke                      m_convStroke;
    233 
    234   PathTransform                   m_pathTransform;
    235   StrokeTransform                 m_strokeTransform;
    236 
    237 public:
    238   Agg2D() :
    239     m_rbuf(),
    240     m_pixFormatPre(m_rbuf),
    241     m_pixFormatCompPre(m_rbuf),
    242     m_renBasePre(m_pixFormatPre),
    243     m_renBaseCompPre(m_pixFormatCompPre),
    244     m_renSolid(m_renBasePre),
    245     m_renSolidComp(m_renBaseCompPre),
    246 
    247     m_allocator(),
    248     m_clipBox(0,0,0,0),
    249 
    250     m_blendMode(BlendSrcOver),
    251     m_imageBlendMode(BlendDst),
    252     m_imageBlendColor(0,0,0),
    253 
    254     m_scanline(),
    255     m_rasterizer(),
    256 
    257     m_masterAlpha(1.0),
    258 
    259     m_color{},
    260     m_gradient{},
    261 
    262     m_lineCap(CapRound),
    263     m_lineJoin(JoinRound),
    264 
    265     m_styleFlag{Solid, Solid},
    266     m_gradientMatrix{},
    267     m_gradientD1{0.0, 0.0},
    268     m_gradientD2{100.0, 100.0},
    269 
    270     m_imageFilter(Bilinear),
    271     m_imageResample(NoResample),
    272     m_imageFilterLut(agg::image_filter_bilinear(), true),
    273 
    274     m_gradientInterpolator{m_gradientMatrix[0], m_gradientMatrix[1]},
    275     m_linearGradientFunction(),
    276     m_radialGradientFunction(),
    277 
    278     m_lineWidth(1),
    279     m_evenOddFlag(false),
    280 
    281     m_path(),
    282     m_transform(),
    283 
    284     m_convCurve(m_path),
    285     m_convStroke(m_convCurve),
    286 
    287     m_pathTransform(m_convCurve, m_transform),
    288     m_strokeTransform(m_convStroke, m_transform)
    289   {
    290     lineCap(m_lineCap);
    291     lineJoin(m_lineJoin);
    292   }
    293 
    294   ~Agg2D() {}
    295 
    296   // Setup
    297   // -----
    298 
    299   void attach(unsigned char* buf, unsigned width, unsigned height, int stride) {
    300     m_rbuf.attach(buf, width, height, stride);
    301     m_renBasePre.reset_clipping(true);
    302     m_renBaseCompPre.reset_clipping(true);
    303 
    304     resetTransformations();
    305     lineWidth(1.0),
    306     lineColor(0,0,0);
    307     fillColor(255,255,255);
    308     clipBox(0, 0, width, height);
    309     lineCap(CapRound);
    310     lineJoin(JoinRound);
    311     imageFilter(Bilinear);
    312     imageResample(NoResample);
    313     m_masterAlpha = 1.0;
    314     m_blendMode = BlendSrcOver;
    315   }
    316 
    317   void attach(Image& img) {
    318     attach(img.renBuf.buf(), img.renBuf.width(), img.renBuf.height(), img.renBuf.stride());
    319   }
    320 
    321   void clipBox(double x1, double y1, double x2, double y2) {
    322     m_clipBox = RectD(x1, y1, x2, y2);
    323     int rx1 = int(x1);
    324     int ry1 = int(y1);
    325     int rx2 = int(x2);
    326     int ry2 = int(y2);
    327 
    328     m_renBasePre.clip_box(rx1, ry1, rx2, ry2);
    329     m_renBaseCompPre.clip_box(rx1, ry1, rx2, ry2);
    330 
    331     m_rasterizer.clip_box(x1, y1, x2, y2);
    332   }
    333 
    334   RectD clipBox() const { return m_clipBox; }
    335 
    336   void clearAll(Color c) {
    337     c.premultiply();
    338     m_renBasePre.fill(c);
    339   }
    340 
    341   void clearAll(unsigned r, unsigned g, unsigned b, unsigned a) {
    342     clearAll(Color(r, g, b, a));
    343   }
    344 
    345   // Conversions
    346   // -----------
    347 
    348   void worldToScreen(double& x, double& y) const { m_transform.transform(&x, &y); }
    349   void screenToWorld(double& x, double& y) const { m_transform.inverse_transform(&x, &y); }
    350 
    351   double worldToScreen(double scalar) const {
    352     double x1 = 0, x2 = scalar;
    353     double y1 = 0, y2 = scalar;
    354     worldToScreen(x1, y1);
    355     worldToScreen(x2, y2);
    356     return std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068;
    357   }
    358 
    359   double screenToWorld(double scalar) const {
    360     double x1 = 0, x2 = scalar;
    361     double y1 = 0, y2 = scalar;
    362     screenToWorld(x1, y1);
    363     screenToWorld(x2, y2);
    364     return std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068;
    365   }
    366 
    367   void alignPoint(double& x, double& y) const {
    368     worldToScreen(x, y);
    369     x = std::floor(x) + 0.5;
    370     y = std::floor(y) + 0.5;
    371     screenToWorld(x, y);
    372   }
    373 
    374   bool inBox(double worldX, double worldY) const {
    375     worldToScreen(worldX, worldY);
    376     return m_renBasePre.inbox(int(worldX), int(worldY));
    377   }
    378 
    379   // General Attributes
    380   // ------------------
    381 
    382   void blendMode(BlendMode m) {
    383     m_blendMode = m;
    384     m_pixFormatCompPre.comp_op(m);
    385   }
    386   BlendMode blendMode() const { return m_blendMode; }
    387 
    388   void imageBlendMode(BlendMode m) { m_imageBlendMode = m; }
    389   BlendMode imageBlendMode() const { return m_imageBlendMode; }
    390 
    391   void imageBlendColor(Color c) { m_imageBlendColor = c; }
    392   void imageBlendColor(unsigned r, unsigned g, unsigned b, unsigned a) { imageBlendColor(Color(r, g, b, a)); }
    393   Color imageBlendColor() const { return m_imageBlendColor; }
    394 
    395   void masterAlpha(double a) { m_masterAlpha = a; }
    396   double masterAlpha() const { return m_masterAlpha; }
    397 
    398   void fillColor(Color c) {
    399     m_color[FillSlot] = c;
    400     m_color[FillSlot].premultiply();
    401     m_styleFlag[FillSlot] = Solid;
    402   }
    403 
    404   void lineColor(Color c) {
    405     m_color[StrokeSlot] = c;
    406     m_color[StrokeSlot].premultiply();
    407     m_styleFlag[StrokeSlot] = Solid;
    408   }
    409 
    410   void fillColor(unsigned r, unsigned g, unsigned b, unsigned a = 0xFFu) { fillColor(Color(r, g, b, a)); }
    411   void lineColor(unsigned r, unsigned g, unsigned b, unsigned a = 0xFFu) { lineColor(Color(r, g, b, a)); }
    412 
    413   void noFill() {
    414     m_color[FillSlot] = Color(0, 0, 0, 0);
    415     m_styleFlag[FillSlot] = None;
    416   }
    417 
    418   void noLine() {
    419     m_color[StrokeSlot] = Color(0, 0, 0, 0);
    420     m_styleFlag[StrokeSlot] = None;
    421   }
    422 
    423   void setLinearGradient(StyleSlot slot, double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) {
    424     int i;
    425 
    426     for (i = 0; i < 128; i++) {
    427       m_gradient[slot][i] = c1.gradient(c2, double(i) / 127.0);
    428       m_gradient[slot][i].premultiply();
    429     }
    430 
    431     for (; i < 256; i++) {
    432       m_gradient[slot][i] = c2.gradient(c3, double(i - 128) / 127.0);
    433       m_gradient[slot][i].premultiply();
    434     }
    435 
    436     double angle = std::atan2(y2-y1, x2-x1);
    437     m_gradientMatrix[slot].reset();
    438     m_gradientMatrix[slot] *= agg::trans_affine_rotation(angle);
    439     m_gradientMatrix[slot] *= agg::trans_affine_translation(x1, y1);
    440     m_gradientMatrix[slot] *= m_transform;
    441     m_gradientMatrix[slot].invert();
    442     m_gradientD1[slot] = 0.0;
    443     m_gradientD2[slot] = std::sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
    444     m_styleFlag[slot] = Linear;
    445     m_color[slot] = Color(0,0,0);  // Set some real color
    446   }
    447 
    448   void fillLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) {
    449     setLinearGradient(FillSlot, x1, y1, x2, y2, c1, c2, c3);
    450   }
    451 
    452   void lineLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) {
    453     setLinearGradient(StrokeSlot, x1, y1, x2, y2, c1, c2, c3);
    454   }
    455 
    456   void setRadialGradient(StyleSlot slot, double x, double y, double r, Color c1, Color c2, Color c3) {
    457     int i;
    458 
    459     for (i = 0; i < 128; i++) {
    460       m_gradient[slot][i] = c1.gradient(c2, double(i) / 127.0);
    461       m_gradient[slot][i].premultiply();
    462     }
    463 
    464     for (; i < 256; i++) {
    465       m_gradient[slot][i] = c2.gradient(c3, double(i - 128) / 127.0);
    466       m_gradient[slot][i].premultiply();
    467     }
    468 
    469     m_gradientD2[slot] = worldToScreen(r);
    470     worldToScreen(x, y);
    471     m_gradientMatrix[slot].reset();
    472     m_gradientMatrix[slot] *= agg::trans_affine_translation(x, y);
    473     m_gradientMatrix[slot].invert();
    474     m_gradientD1[slot] = 0;
    475     m_styleFlag[slot] = Radial;
    476     m_color[slot] = Color(0,0,0);  // Set some real color
    477   }
    478 
    479   void fillRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) {
    480     setRadialGradient(FillSlot, x, y, r, c1, c2, c3);
    481   }
    482 
    483   void lineRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) {
    484     setRadialGradient(StrokeSlot, x, y, r, c1, c2, c3);
    485   }
    486 
    487   void lineWidth(double w) {
    488       m_lineWidth = w;
    489       m_convStroke.width(w);
    490   }
    491 
    492   void fillEvenOdd(bool evenOddFlag) {
    493     m_evenOddFlag = evenOddFlag;
    494     m_rasterizer.filling_rule(evenOddFlag ? agg::fill_even_odd : agg::fill_non_zero);
    495   }
    496 
    497   void lineCap(LineCap cap) {
    498       m_lineCap = cap;
    499       m_convStroke.line_cap((agg::line_cap_e)cap);
    500   }
    501 
    502   void lineJoin(LineJoin join) {
    503     m_lineJoin = join;
    504     m_convStroke.line_join((agg::line_join_e)join);
    505   }
    506 
    507   double lineWidth(double w) const { return m_lineWidth; }
    508   bool fillEvenOdd() const { return m_evenOddFlag; }
    509   LineCap lineCap() const { return m_lineCap; }
    510   LineJoin lineJoin() const { return m_lineJoin; }
    511 
    512   // Transformations
    513   // ---------------
    514 
    515   Transformations transformations() const {
    516     Transformations tr;
    517     m_transform.store_to(tr.affineMatrix);
    518     return tr;
    519   }
    520 
    521   void transformations(const Transformations& tr) {
    522     m_transform.load_from(tr.affineMatrix);
    523     m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
    524     m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
    525   }
    526 
    527   void resetTransformations() {
    528     m_transform.reset();
    529   }
    530 
    531   void rotate(double angle) { m_transform *= agg::trans_affine_rotation(angle); }
    532   void skew(double sx, double sy) { m_transform *= agg::trans_affine_skewing(sx, sy); }
    533   void translate(double x, double y) { m_transform *= agg::trans_affine_translation(x, y); }
    534 
    535   void affine(const Affine& tr) {
    536     m_transform *= tr;
    537     m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
    538     m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
    539   }
    540 
    541   void affine(const Transformations& tr) {
    542     affine(agg::trans_affine(tr.affineMatrix[0], tr.affineMatrix[1], tr.affineMatrix[2],
    543                             tr.affineMatrix[3], tr.affineMatrix[4], tr.affineMatrix[5]));
    544   }
    545 
    546   void scale(double sx, double sy) {
    547     m_transform *= agg::trans_affine_scaling(sx, sy);
    548     m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
    549     m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
    550   }
    551 
    552   // Basic Shapes
    553   // ------------
    554 
    555   void fillRectangleI(int x1, int y1, int x2, int y2, Color color);
    556 
    557   void line(double x1, double y1, double x2, double y2);
    558   void triangle(double x1, double y1, double x2, double y2, double x3, double y3);
    559   void rectangle(double x1, double y1, double x2, double y2);
    560   void roundedRect(double x1, double y1, double x2, double y2, double r);
    561   void roundedRect(double x1, double y1, double x2, double y2, double rx, double ry);
    562   void roundedRect(double x1, double y1, double x2, double y2,
    563                     double rxBottom, double ryBottom,
    564                     double rxTop,    double ryTop);
    565   void ellipse(double cx, double cy, double rx, double ry);
    566   void arc(double cx, double cy, double rx, double ry, double start, double sweep);
    567   void star(double cx, double cy, double r1, double r2, double startAngle, int numRays);
    568   void curve(double x1, double y1, double x2, double y2, double x3, double y3);
    569   void curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4);
    570   void polygon(double* xy, int numPoints);
    571   void polyline(double* xy, int numPoints);
    572 
    573 
    574   // Path commands
    575   // -------------
    576 
    577   void resetPath() { m_path.remove_all(); }
    578   void moveTo(double x, double y) { m_path.move_to(x, y); }
    579   void moveRel(double dx, double dy) { m_path.move_rel(dx, dy); }
    580   void lineTo(double x, double y) { m_path.line_to(x, y); }
    581   void lineRel(double dx, double dy) { m_path.line_rel(dx, dy); }
    582   void horLineTo(double x) { m_path.hline_to(x); }
    583   void horLineRel(double dx) { m_path.hline_rel(dx); }
    584   void verLineTo(double y) { m_path.vline_to(y); }
    585   void verLineRel(double dy) { m_path.vline_rel(dy); }
    586   void arcTo(double rx, double ry, double angle, bool laFlag, bool sweepFlag, double x, double y) { m_path.arc_to(rx, ry, angle, laFlag, sweepFlag, x, y); }
    587   void arcRel(double rx, double ry, double angle, bool laFlag, bool sweepFlag, double dx, double dy) { m_path.arc_rel(rx, ry, angle, laFlag, sweepFlag, dx, dy); }
    588   void quadricCurveTo(double x0, double y0, double x1, double y1) { m_path.curve3(x0, y0, x1, y1); }
    589   void quadricCurveRel(double x0, double y0, double x1, double y1) { m_path.curve3_rel(x0, y0, x1, y1); }
    590   void quadricCurveTo(double x1, double y1) { m_path.curve3(x1, y1); }
    591   void quadricCurveRel(double x1, double y1) { m_path.curve3_rel(x1, y1); }
    592   void cubicCurveTo(double x0, double y0, double x1, double y1, double x2, double y2) { m_path.curve4(x0, y0, x1, y1, x2, y2); }
    593   void cubicCurveRel(double x0, double y0, double x1, double y1, double x2, double y2) { m_path.curve4_rel(x0, y0, x1, y1, x2, y2); }
    594   void cubicCurveTo(double x1, double y1, double x2, double y2) { m_path.curve4(x1, y1, x2, y2); }
    595   void cubicCurveRel(double x1, double y1, double x2, double y2) { m_path.curve4_rel(x1, y1, x2, y2); }
    596 
    597   void addEllipse(double cx, double cy, double rx, double ry, Direction dir) {
    598     agg::bezier_arc arc(cx, cy, rx, ry, 0, (dir == CCW) ? 2*pi() : -2*pi());
    599     m_path.concat_path(arc,0);
    600     m_path.close_polygon();
    601   }
    602 
    603   void closePolygon() { m_path.close_polygon(); }
    604 
    605   void drawPath(DrawPathFlag flag = FillAndStroke);
    606   void drawPathNoTransform(DrawPathFlag flag = FillAndStroke);
    607 
    608 
    609   // Image Transformations
    610   // ---------------------
    611 
    612   void imageFilter(ImageFilter f);
    613   ImageFilter imageFilter() const { return m_imageFilter; }
    614 
    615   void imageResample(ImageResample f) { m_imageResample = f; }
    616   ImageResample imageResample() const { return m_imageResample; }
    617 
    618   void transformImage(const Image& img,
    619     int imgX1, int imgY1, int imgX2, int imgY2,
    620     double dstX1, double dstY1, double dstX2, double dstY2);
    621 
    622   void transformImage(const Image& img,
    623     double dstX1, double dstY1, double dstX2, double dstY2);
    624 
    625   void transformImage(const Image& img,
    626     int imgX1, int imgY1, int imgX2, int imgY2,
    627     const double* parallelogram);
    628 
    629   void transformImage(const Image& img, const double* parallelogram);
    630 
    631   void transformImagePath(const Image& img,
    632     int imgX1,    int imgY1,    int imgX2,    int imgY2,
    633     double dstX1, double dstY1, double dstX2, double dstY2);
    634 
    635   void transformImagePath(const Image& img,
    636     double dstX1, double dstY1, double dstX2, double dstY2);
    637 
    638   void transformImagePath(const Image& img,
    639     int imgX1, int imgY1, int imgX2, int imgY2,
    640     const double* parallelogram);
    641 
    642   void transformImagePath(const Image& img, const double* parallelogram);
    643 
    644   // Image Blending (no transformations available)
    645   void blendImage(Image& img,
    646     int imgX1, int imgY1, int imgX2, int imgY2,
    647     double dstX, double dstY, unsigned alpha=255);
    648   void blendImage(Image& img, double dstX, double dstY, unsigned alpha=255);
    649 
    650   // Copy image directly, together with alpha-channel
    651   void copyImage(Image& img,
    652     int imgX1, int imgY1, int imgX2, int imgY2,
    653     double dstX, double dstY);
    654   void copyImage(Image& img, double dstX, double dstY);
    655 
    656   // Auxiliary
    657   // ---------
    658 
    659   static inline double pi() { return agg::pi; }
    660   static inline double deg2Rad(double v) { return v * agg::pi / 180.0; }
    661   static inline double rad2Deg(double v) { return v * 180.0 / agg::pi; }
    662 
    663 private:
    664   void render(StyleSlot slot);
    665   void addLine(double x1, double y1, double x2, double y2);
    666   void renderImage(const Image& img, int x1, int y1, int x2, int y2, const double* parl);
    667 };
    668 
    669 inline bool operator==(const Agg2D::Color& c1, const Agg2D::Color& c2) { return c1.r == c2.r && c1.g == c2.g && c1.b == c2.b && c1.a == c2.a; }
    670 inline bool operator!=(const Agg2D::Color& c1, const Agg2D::Color& c2) { return !(c1 == c2); }
    671 
    672 void Agg2D::addLine(double x1, double y1, double x2, double y2) {
    673   m_path.move_to(x1, y1);
    674   m_path.line_to(x2, y2);
    675 }
    676 
    677 void Agg2D::fillRectangleI(int x1, int y1, int x2, int y2, Color color) {
    678   color.premultiply();
    679 
    680   if (m_blendMode == BlendSrc) {
    681     m_renBasePre.copy_bar(x1, y1, x2, y2, color);
    682   }
    683   else if (m_blendMode == BlendSrcOver) {
    684     m_renBasePre.blend_bar(x1, y1, x2, y2, color, 0xFF);
    685   }
    686   else {
    687     m_renBaseCompPre.blend_bar(x1, y1, x2, y2, color, 0xFF);
    688   }
    689 }
    690 
    691 void Agg2D::line(double x1, double y1, double x2, double y2) {
    692   m_path.remove_all();
    693   addLine(x1, y1, x2, y2);
    694   drawPath(StrokeOnly);
    695 }
    696 
    697 void Agg2D::triangle(double x1, double y1, double x2, double y2, double x3, double y3) {
    698   m_path.remove_all();
    699   m_path.move_to(x1, y1);
    700   m_path.line_to(x2, y2);
    701   m_path.line_to(x3, y3);
    702   m_path.close_polygon();
    703   drawPath(FillAndStroke);
    704 }
    705 
    706 void Agg2D::rectangle(double x1, double y1, double x2, double y2) {
    707   m_path.remove_all();
    708   m_path.move_to(x1, y1);
    709   m_path.line_to(x2, y1);
    710   m_path.line_to(x2, y2);
    711   m_path.line_to(x1, y2);
    712   m_path.close_polygon();
    713   drawPath(FillAndStroke);
    714 }
    715 
    716 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double r) {
    717   m_path.remove_all();
    718   agg::rounded_rect rc(x1, y1, x2, y2, r);
    719   rc.normalize_radius();
    720   rc.approximation_scale(worldToScreen(1.0) * g_approxScale);
    721   m_path.concat_path(rc,0);
    722   drawPath(FillAndStroke);
    723 }
    724 
    725 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double rx, double ry) {
    726   m_path.remove_all();
    727   agg::rounded_rect rc;
    728   rc.rect(x1, y1, x2, y2);
    729   rc.radius(rx, ry);
    730   rc.normalize_radius();
    731   m_path.concat_path(rc,0);
    732   drawPath(FillAndStroke);
    733 }
    734 
    735 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double rx_bottom, double ry_bottom, double rx_top, double ry_top) {
    736   m_path.remove_all();
    737   agg::rounded_rect rc;
    738   rc.rect(x1, y1, x2, y2);
    739   rc.radius(rx_bottom, ry_bottom, rx_top, ry_top);
    740   rc.normalize_radius();
    741   rc.approximation_scale(worldToScreen(1.0) * g_approxScale);
    742   m_path.concat_path(rc,0);
    743   drawPath(FillAndStroke);
    744 }
    745 
    746 void Agg2D::ellipse(double cx, double cy, double rx, double ry) {
    747   m_path.remove_all();
    748   agg::bezier_arc arc(cx, cy, rx, ry, 0, 2*pi());
    749   m_path.concat_path(arc,0);
    750   m_path.close_polygon();
    751   drawPath(FillAndStroke);
    752 }
    753 
    754 void Agg2D::arc(double cx, double cy, double rx, double ry, double start, double sweep) {
    755   m_path.remove_all();
    756   agg::bezier_arc arc(cx, cy, rx, ry, start, sweep);
    757   m_path.concat_path(arc,0);
    758   drawPath(StrokeOnly);
    759 }
    760 
    761 void Agg2D::star(double cx, double cy, double r1, double r2, double startAngle, int numRays) {
    762   m_path.remove_all();
    763   double da = agg::pi / double(numRays);
    764   double a = startAngle;
    765   for (int i = 0; i < numRays; i++) {
    766     double x = cos(a) * r2 + cx;
    767     double y = sin(a) * r2 + cy;
    768     if (i) m_path.line_to(x, y);
    769     else   m_path.move_to(x, y);
    770     a += da;
    771     m_path.line_to(cos(a) * r1 + cx, sin(a) * r1 + cy);
    772     a += da;
    773   }
    774   closePolygon();
    775   drawPath(FillAndStroke);
    776 }
    777 
    778 void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3) {
    779   m_path.remove_all();
    780   m_path.move_to(x1, y1);
    781   m_path.curve3(x2, y2, x3, y3);
    782   drawPath(StrokeOnly);
    783 }
    784 
    785 void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
    786   m_path.remove_all();
    787   m_path.move_to(x1, y1);
    788   m_path.curve4(x2, y2, x3, y3, x4, y4);
    789   drawPath(StrokeOnly);
    790 }
    791 
    792 void Agg2D::polygon(double* xy, int numPoints) {
    793   m_path.remove_all();
    794   m_path.concat_poly(xy,0,true);
    795   closePolygon();
    796   drawPath(FillAndStroke);
    797 }
    798 
    799 void Agg2D::polyline(double* xy, int numPoints) {
    800   m_path.remove_all();
    801   m_path.concat_poly(xy,0,true);
    802   drawPath(StrokeOnly);
    803 }
    804 
    805 void Agg2D::imageFilter(ImageFilter f) {
    806   m_imageFilter = f;
    807   switch(f) {
    808     case NoFilter: break;
    809     case Bilinear: m_imageFilterLut.calculate(agg::image_filter_bilinear(), true); break;
    810   }
    811 }
    812 
    813 void Agg2D::transformImage(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX1, double dstY1, double dstX2, double dstY2) {
    814   resetPath();
    815   moveTo(dstX1, dstY1);
    816   lineTo(dstX2, dstY1);
    817   lineTo(dstX2, dstY2);
    818   lineTo(dstX1, dstY2);
    819   closePolygon();
    820   double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
    821   renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
    822 }
    823 
    824 void Agg2D::transformImage(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2) {
    825   resetPath();
    826   moveTo(dstX1, dstY1);
    827   lineTo(dstX2, dstY1);
    828   lineTo(dstX2, dstY2);
    829   lineTo(dstX1, dstY2);
    830   closePolygon();
    831   double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
    832   renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
    833 }
    834 
    835 void Agg2D::transformImage(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, const double* parallelogram) {
    836   resetPath();
    837   moveTo(parallelogram[0], parallelogram[1]);
    838   lineTo(parallelogram[2], parallelogram[3]);
    839   lineTo(parallelogram[4], parallelogram[5]);
    840   lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2], parallelogram[1] + parallelogram[5] - parallelogram[3]);
    841   closePolygon();
    842   renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
    843 }
    844 
    845 
    846 void Agg2D::transformImage(const Image& img, const double* parallelogram) {
    847   resetPath();
    848   moveTo(parallelogram[0], parallelogram[1]);
    849   lineTo(parallelogram[2], parallelogram[3]);
    850   lineTo(parallelogram[4], parallelogram[5]);
    851   lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2], parallelogram[1] + parallelogram[5] - parallelogram[3]);
    852   closePolygon();
    853   renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
    854 }
    855 
    856 void Agg2D::transformImagePath(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX1, double dstY1, double dstX2, double dstY2) {
    857   double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
    858   renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
    859 }
    860 
    861 void Agg2D::transformImagePath(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2) {
    862   double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
    863   renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
    864 }
    865 
    866 void Agg2D::transformImagePath(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, const double* parallelogram) {
    867   renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
    868 }
    869 
    870 void Agg2D::transformImagePath(const Image& img, const double* parallelogram) {
    871   renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
    872 }
    873 
    874 void Agg2D::drawPath(DrawPathFlag flag) {
    875   m_rasterizer.reset();
    876   switch(flag) {
    877     case FillOnly:
    878       if (m_styleFlag[FillSlot] != None) {
    879         m_rasterizer.add_path(m_pathTransform);
    880         render(FillSlot);
    881       }
    882       break;
    883 
    884     case StrokeOnly:
    885       if (m_styleFlag[StrokeSlot] != None && m_lineWidth > 0.0) {
    886         m_rasterizer.add_path(m_strokeTransform);
    887         render(StrokeSlot);
    888       }
    889       break;
    890 
    891     case FillAndStroke:
    892       if (m_styleFlag[FillSlot] != None) {
    893         m_rasterizer.add_path(m_pathTransform);
    894         render(FillSlot);
    895       }
    896 
    897       if (m_styleFlag[StrokeSlot] != None && m_lineWidth > 0.0) {
    898         m_rasterizer.add_path(m_strokeTransform);
    899         render(StrokeSlot);
    900       }
    901       break;
    902 
    903     case FillWithLineColor:
    904       if (m_styleFlag[StrokeSlot] != None) {
    905         m_rasterizer.add_path(m_pathTransform);
    906         render(StrokeSlot);
    907       }
    908       break;
    909   }
    910 }
    911 
    912 class Agg2DRenderer {
    913 public:
    914   template<class BaseRenderer, class SolidRenderer>
    915   void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Agg2D::StyleSlot slot) {
    916     typedef agg::span_allocator<agg::rgba8> span_allocator_type;
    917     typedef agg::renderer_scanline_aa<BaseRenderer, span_allocator_type, Agg2D::LinearGradientSpan> RendererLinearGradient;
    918     typedef agg::renderer_scanline_aa<BaseRenderer, span_allocator_type, Agg2D::RadialGradientSpan> RendererRadialGradient;
    919 
    920     switch (gr.m_styleFlag[slot]) {
    921       case Agg2D::None: {
    922         return;
    923       }
    924 
    925       case Agg2D::Solid: {
    926         renSolid.color(gr.m_color[slot]);
    927         agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, renSolid);
    928         return;
    929       }
    930 
    931       case Agg2D::Linear: {
    932         Agg2D::LinearGradientSpan span(/*gr.m_allocator, */
    933                                        gr.m_gradientInterpolator[slot],
    934                                        gr.m_linearGradientFunction,
    935                                        gr.m_gradient[slot],
    936                                        gr.m_gradientD1[slot],
    937                                        gr.m_gradientD2[slot]);
    938         RendererLinearGradient ren(renBase,gr.m_allocator,span);
    939         agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
    940         return;
    941       }
    942 
    943       case Agg2D::Radial: {
    944         Agg2D::RadialGradientSpan span(/*gr.m_allocator, */
    945                                        gr.m_gradientInterpolator[slot],
    946                                        gr.m_radialGradientFunction,
    947                                        gr.m_gradient[slot],
    948                                        gr.m_gradientD1[slot],
    949                                        gr.m_gradientD2[slot]);
    950         RendererRadialGradient ren(renBase,gr.m_allocator,span);
    951         agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
    952         return;
    953       }
    954     }
    955   }
    956 
    957   class SpanConvImageBlend {
    958   private:
    959     Agg2D::BlendMode m_mode;
    960     Agg2D::Color m_color;
    961 
    962   public:
    963     SpanConvImageBlend(Agg2D::BlendMode m, Agg2D::Color c) :
    964         m_mode(m), m_color(c) {}
    965 
    966     void convert(Agg2D::Color* span, int x, int y, unsigned len) const {
    967       unsigned l2;
    968       Agg2D::Color* s2;
    969       if (m_mode != Agg2D::BlendDst) {
    970         l2 = len;
    971         s2 = span;
    972         typedef agg::comp_op_adaptor_clip_to_dst_rgba_pre<Agg2D::Color, agg::order_rgba> OpType;
    973         do {
    974           OpType::blend_pix(m_mode, (Agg2D::Color::value_type*)s2, m_color.r, m_color.g, m_color.b, Agg2D::Color::base_mask, agg::cover_full);
    975           ++s2;
    976         }
    977         while(--l2);
    978       }
    979       if (m_color.a < Agg2D::Color::base_mask) {
    980         l2 = len;
    981         s2 = span;
    982         unsigned a = m_color.a;
    983         do {
    984           s2->r = (s2->r * a) >> Agg2D::Color::base_shift;
    985           s2->g = (s2->g * a) >> Agg2D::Color::base_shift;
    986           s2->b = (s2->b * a) >> Agg2D::Color::base_shift;
    987           s2->a = (s2->a * a) >> Agg2D::Color::base_shift;
    988           ++s2;
    989         }
    990         while(--l2);
    991       }
    992     }
    993   };
    994 
    995   template<class BaseRenderer, class SolidRenderer, class Rasterizer, class Scanline>
    996   void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Rasterizer& ras, Scanline& sl) {
    997     typedef agg::span_allocator<agg::rgba8> span_allocator_type;
    998     typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::LinearGradientSpan> RendererLinearGradient;
    999     typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::RadialGradientSpan> RendererRadialGradient;
   1000 
   1001     int slot = 0;
   1002 
   1003     switch (gr.m_styleFlag[slot]) {
   1004       case Agg2D::None: {
   1005         return;
   1006       }
   1007 
   1008       case Agg2D::Solid: {
   1009         renSolid.color(gr.m_color[slot]);
   1010         agg::render_scanlines(ras, sl, renSolid);
   1011         return;
   1012       }
   1013 
   1014       case Agg2D::Linear: {
   1015         Agg2D::LinearGradientSpan span(gr.m_gradientInterpolator[slot],
   1016                                        gr.m_linearGradientFunction,
   1017                                        gr.m_gradient[slot],
   1018                                        gr.m_gradientD1[slot],
   1019                                        gr.m_gradientD2[slot]);
   1020         RendererLinearGradient ren(renBase,gr.m_allocator,span);
   1021         agg::render_scanlines(ras, sl, ren);
   1022         return;
   1023       }
   1024 
   1025       case Agg2D::Radial: {
   1026         Agg2D::RadialGradientSpan span(gr.m_gradientInterpolator[slot],
   1027                                        gr.m_radialGradientFunction,
   1028                                        gr.m_gradient[slot],
   1029                                        gr.m_gradientD1[slot],
   1030                                        gr.m_gradientD2[slot]);
   1031         RendererRadialGradient ren(renBase,gr.m_allocator,span);
   1032         agg::render_scanlines(ras, sl, ren);
   1033         return;
   1034       }
   1035     }
   1036   }
   1037 
   1038   template<class BaseRenderer, class Interpolator>
   1039   static void renderImage(Agg2D& gr, const Agg2D::Image& img, BaseRenderer& renBase, Interpolator& interpolator) {
   1040     Agg2D::Image& imgc = const_cast<Agg2D::Image&>(img);
   1041     Agg2D::PixFormatPre img_pixf(imgc.renBuf);
   1042     typedef agg::image_accessor_clone<Agg2D::PixFormatPre> img_source_type;
   1043     img_source_type source(img_pixf);
   1044 
   1045     SpanConvImageBlend blend(gr.m_imageBlendMode, gr.m_imageBlendColor);
   1046     if (gr.m_imageFilter == Agg2D::NoFilter) {
   1047       typedef agg::span_image_filter_rgba_nn<img_source_type,Interpolator> SpanGenType;
   1048       typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
   1049       typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType;
   1050 
   1051       SpanGenType sg(source,interpolator);
   1052       SpanConvType sc(sg, blend);
   1053       RendererType ri(renBase,gr.m_allocator,sg);
   1054       agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
   1055     }
   1056     else {
   1057       bool resample = (gr.m_imageResample == Agg2D::ResampleAlways);
   1058       if (gr.m_imageResample == Agg2D::ResampleOnZoomOut) {
   1059         double sx, sy;
   1060         interpolator.transformer().scaling_abs(&sx,&sy);
   1061         if (sx > 1.125 || sy > 1.125) {
   1062           resample = true;
   1063         }
   1064       }
   1065 
   1066       if (resample) {
   1067         typedef agg::span_image_resample_rgba_affine<img_source_type> SpanGenType;
   1068         typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
   1069         typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType;
   1070 
   1071         SpanGenType sg(source,interpolator,gr.m_imageFilterLut);
   1072         SpanConvType sc(sg, blend);
   1073         RendererType ri(renBase,gr.m_allocator,sg);
   1074         agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
   1075       }
   1076       else {
   1077         typedef agg::span_image_filter_rgba_bilinear<img_source_type,Interpolator> SpanGenType;
   1078         typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
   1079         typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType;
   1080 
   1081         SpanGenType sg(source,interpolator);
   1082         SpanConvType sc(sg, blend);
   1083         RendererType ri(renBase,gr.m_allocator,sg);
   1084         agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
   1085       }
   1086     }
   1087   }
   1088 };
   1089 
   1090 void Agg2D::render(StyleSlot slot) {
   1091   if (m_blendMode == BlendSrcOver)
   1092     Agg2DRenderer::render(*this, m_renBasePre, m_renSolidComp, slot);
   1093   else
   1094     Agg2DRenderer::render(*this, m_renBaseCompPre, m_renSolidComp, slot);
   1095 }
   1096 
   1097 void Agg2D::renderImage(const Image& img, int x1, int y1, int x2, int y2, const double* parl) {
   1098   agg::trans_affine mtx((double)x1, (double)y1, (double)x2, (double)y2, parl);
   1099   mtx *= m_transform;
   1100   mtx.invert();
   1101 
   1102   m_rasterizer.reset();
   1103   m_rasterizer.add_path(m_pathTransform);
   1104 
   1105   typedef agg::span_interpolator_linear<agg::trans_affine> Interpolator;
   1106   Interpolator interpolator(mtx);
   1107 
   1108   Agg2DRenderer::renderImage(*this,img, m_renBaseCompPre, interpolator);
   1109 }
   1110 
   1111 void Agg2D::blendImage(Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX, double dstY, unsigned alpha) {
   1112   worldToScreen(dstX, dstY);
   1113   PixFormatPre pixF(img.renBuf);
   1114   Rect r(imgX1, imgY1, imgX2, imgY2);
   1115   m_renBaseCompPre.blend_from(pixF, &r, int(dstX)-imgX1, int(dstY)-imgY1, alpha);
   1116 }
   1117 
   1118 void Agg2D::blendImage(Image& img, double dstX, double dstY, unsigned alpha) {
   1119   worldToScreen(dstX, dstY);
   1120   PixFormatPre pixF(img.renBuf);
   1121   m_renBasePre.blend_from(pixF, 0, int(dstX), int(dstY), alpha);
   1122   m_renBaseCompPre.blend_from(pixF, 0, int(dstX), int(dstY), alpha);
   1123 }
   1124 
   1125 void Agg2D::copyImage(Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX, double dstY) {
   1126   worldToScreen(dstX, dstY);
   1127   Rect r(imgX1, imgY1, imgX2, imgY2);
   1128   m_renBasePre.copy_from(img.renBuf, &r, int(dstX)-imgX1, int(dstY)-imgY1);
   1129 }
   1130 
   1131 void Agg2D::copyImage(Image& img, double dstX, double dstY) {
   1132   worldToScreen(dstX, dstY);
   1133   m_renBasePre.copy_from(img.renBuf, 0, int(dstX), int(dstY));
   1134 }
   1135 
   1136 // AGG Benchmarking - Backend Implementation
   1137 // =========================================
   1138 
   1139 namespace blbench {
   1140 
   1141 static inline uint32_t to_agg2d_blend_mode(BLCompOp comp_op) {
   1142   switch (comp_op) {
   1143     case BL_COMP_OP_CLEAR      : return uint32_t(Agg2D::BlendClear); break;
   1144     case BL_COMP_OP_SRC_COPY   : return uint32_t(Agg2D::BlendSrc); break;
   1145     case BL_COMP_OP_DST_COPY   : return uint32_t(Agg2D::BlendDst); break;
   1146     case BL_COMP_OP_SRC_OVER   : return uint32_t(Agg2D::BlendSrcOver); break;
   1147     case BL_COMP_OP_DST_OVER   : return uint32_t(Agg2D::BlendDstOver); break;
   1148     case BL_COMP_OP_SRC_IN     : return uint32_t(Agg2D::BlendSrcIn); break;
   1149     case BL_COMP_OP_DST_IN     : return uint32_t(Agg2D::BlendDstIn); break;
   1150     case BL_COMP_OP_SRC_OUT    : return uint32_t(Agg2D::BlendSrcOut); break;
   1151     case BL_COMP_OP_DST_OUT    : return uint32_t(Agg2D::BlendDstOut); break;
   1152     case BL_COMP_OP_SRC_ATOP   : return uint32_t(Agg2D::BlendSrcAtop); break;
   1153     case BL_COMP_OP_DST_ATOP   : return uint32_t(Agg2D::BlendDstAtop); break;
   1154     case BL_COMP_OP_XOR        : return uint32_t(Agg2D::BlendXor); break;
   1155     case BL_COMP_OP_PLUS       : return uint32_t(Agg2D::BlendAdd); break;
   1156     case BL_COMP_OP_MULTIPLY   : return uint32_t(Agg2D::BlendMultiply); break;
   1157     case BL_COMP_OP_SCREEN     : return uint32_t(Agg2D::BlendScreen); break;
   1158     case BL_COMP_OP_OVERLAY    : return uint32_t(Agg2D::BlendOverlay); break;
   1159     case BL_COMP_OP_DARKEN     : return uint32_t(Agg2D::BlendDarken); break;
   1160     case BL_COMP_OP_LIGHTEN    : return uint32_t(Agg2D::BlendLighten); break;
   1161     case BL_COMP_OP_COLOR_DODGE: return uint32_t(Agg2D::BlendColorDodge); break;
   1162     case BL_COMP_OP_COLOR_BURN : return uint32_t(Agg2D::BlendColorBurn); break;
   1163     case BL_COMP_OP_HARD_LIGHT : return uint32_t(Agg2D::BlendHardLight); break;
   1164     case BL_COMP_OP_SOFT_LIGHT : return uint32_t(Agg2D::BlendSoftLight); break;
   1165     case BL_COMP_OP_DIFFERENCE : return uint32_t(Agg2D::BlendDifference); break;
   1166     case BL_COMP_OP_EXCLUSION  : return uint32_t(Agg2D::BlendExclusion); break;
   1167 
   1168     default:
   1169       return 0xFFFFFFFFu;
   1170   }
   1171 }
   1172 
   1173 static inline Agg2D::Color to_agg2d_color(BLRgba32 rgba32) {
   1174   return Agg2D::Color(rgba32.r(), rgba32.g(), rgba32.b(), rgba32.a());
   1175 }
   1176 
   1177 struct AggModule : public Backend {
   1178   Agg2D _ctx;
   1179 
   1180   AggModule();
   1181   ~AggModule() override;
   1182 
   1183   bool supports_comp_op(BLCompOp comp_op) const override;
   1184   bool supports_style(StyleKind style) const override;
   1185 
   1186   void before_run() override;
   1187   void flush() override;
   1188   void after_run() override;
   1189 
   1190   void prepare_fill_stroke_option(RenderOp op);
   1191 
   1192   template<typename RectT>
   1193   void setup_style(RenderOp op, const RectT& rect);
   1194 
   1195   void render_rect_a(RenderOp op) override;
   1196   void render_rect_f(RenderOp op) override;
   1197   void render_rect_rotated(RenderOp op) override;
   1198   void render_round_f(RenderOp op) override;
   1199   void render_round_rotated(RenderOp op) override;
   1200   void render_polygon(RenderOp op, uint32_t complexity) override;
   1201   void render_shape(RenderOp op, ShapeData shape) override;
   1202 };
   1203 
   1204 AggModule::AggModule() {
   1205   strcpy(_name, "AGG");
   1206 }
   1207 AggModule::~AggModule() {}
   1208 
   1209 bool AggModule::supports_comp_op(BLCompOp comp_op) const {
   1210   return to_agg2d_blend_mode(comp_op) != 0xFFFFFFFFu;
   1211 }
   1212 
   1213 bool AggModule::supports_style(StyleKind style) const {
   1214   return style == StyleKind::kSolid         ||
   1215          style == StyleKind::kLinearPad     ||
   1216          style == StyleKind::kLinearRepeat  ||
   1217          style == StyleKind::kLinearReflect ||
   1218          style == StyleKind::kRadialPad     ||
   1219          style == StyleKind::kRadialRepeat  ||
   1220          style == StyleKind::kRadialReflect ;
   1221 }
   1222 
   1223 void AggModule::before_run() {
   1224   int w = int(_params.screen_w);
   1225   int h = int(_params.screen_h);
   1226 
   1227   BLImageData surface_data;
   1228   _surface.create(w, h, BL_FORMAT_PRGB32);
   1229   _surface.make_mutable(&surface_data);
   1230 
   1231   _ctx.attach(
   1232     static_cast<unsigned char*>(surface_data.pixel_data),
   1233     unsigned(surface_data.size.w),
   1234     unsigned(surface_data.size.h),
   1235     int(surface_data.stride));
   1236 
   1237   _ctx.fillEvenOdd(false);
   1238   _ctx.noLine();
   1239   _ctx.blendMode(Agg2D::BlendSrc);
   1240   _ctx.clearAll(Agg2D::Color(0, 0, 0, 0));
   1241   _ctx.blendMode(Agg2D::BlendMode(to_agg2d_blend_mode(_params.comp_op)));
   1242 }
   1243 
   1244 void AggModule::flush() {
   1245   // Nothing...
   1246 }
   1247 
   1248 void AggModule::after_run() {
   1249   _ctx.attach(nullptr, 0, 0, 0);
   1250 }
   1251 
   1252 void AggModule::prepare_fill_stroke_option(RenderOp op) {
   1253   if (op == RenderOp::kStroke)
   1254     _ctx.noFill();
   1255   else
   1256     _ctx.noLine();
   1257 }
   1258 
   1259 template<typename RectT>
   1260 void AggModule::setup_style(RenderOp op, const RectT& rect) {
   1261   switch (_params.style) {
   1262     case StyleKind::kSolid: {
   1263       BLRgba32 color = _rnd_color.next_rgba32();
   1264       if (op == RenderOp::kStroke)
   1265         _ctx.lineColor(to_agg2d_color(color));
   1266       else
   1267         _ctx.fillColor(to_agg2d_color(color));
   1268       break;
   1269     }
   1270 
   1271     case StyleKind::kLinearPad:
   1272     case StyleKind::kLinearRepeat:
   1273     case StyleKind::kLinearReflect: {
   1274       double x1 = rect.x + rect.w * 0.2;
   1275       double y1 = rect.y + rect.h * 0.2;
   1276       double x2 = rect.x + rect.w * 0.8;
   1277       double y2 = rect.y + rect.h * 0.8;
   1278 
   1279       BLRgba32 c1 = _rnd_color.next_rgba32();
   1280       BLRgba32 c2 = _rnd_color.next_rgba32();
   1281       BLRgba32 c3 = _rnd_color.next_rgba32();
   1282 
   1283       if (op == RenderOp::kStroke)
   1284         _ctx.lineLinearGradient(x1, y1, x2, y2, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3));
   1285       else
   1286         _ctx.fillLinearGradient(x1, y1, x2, y2, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3));
   1287       break;
   1288     }
   1289 
   1290     case StyleKind::kRadialPad:
   1291     case StyleKind::kRadialRepeat:
   1292     case StyleKind::kRadialReflect: {
   1293       double cx = rect.x + rect.w / 2.0;
   1294       double cy = rect.y + rect.h / 2.0;
   1295       double cr = (rect.w + rect.h) / 4.0;
   1296 
   1297       BLRgba32 c1 = _rnd_color.next_rgba32();
   1298       BLRgba32 c2 = _rnd_color.next_rgba32();
   1299       BLRgba32 c3 = _rnd_color.next_rgba32();
   1300 
   1301       if (op == RenderOp::kStroke)
   1302         _ctx.lineRadialGradient(cx, cy, cr, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3));
   1303       else
   1304         _ctx.fillRadialGradient(cx, cy, cr, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3));
   1305       break;
   1306     }
   1307 
   1308     default:
   1309       break;
   1310   }
   1311 }
   1312 
   1313 void AggModule::render_rect_a(RenderOp op) {
   1314   BLSizeI bounds(_params.screen_w, _params.screen_h);
   1315   StyleKind style = _params.style;
   1316   int wh = _params.shape_size;
   1317 
   1318   prepare_fill_stroke_option(op);
   1319 
   1320   if (_params.style == StyleKind::kSolid && op != RenderOp::kStroke) {
   1321     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1322       BLRectI rect = _rnd_coord.next_rect_i(bounds, wh, wh);
   1323       _ctx.fillRectangleI(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, to_agg2d_color(_rnd_color.next_rgba32()));
   1324     }
   1325   }
   1326   else {
   1327     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1328       BLRectI rect = _rnd_coord.next_rect_i(bounds, wh, wh);
   1329       setup_style(op, rect);
   1330       _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h);
   1331     }
   1332   }
   1333 }
   1334 
   1335 void AggModule::render_rect_f(RenderOp op) {
   1336   BLSize bounds(_params.screen_w, _params.screen_h);
   1337   StyleKind style = _params.style;
   1338   double wh = _params.shape_size;
   1339 
   1340   prepare_fill_stroke_option(op);
   1341 
   1342   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1343     BLRect rect = _rnd_coord.next_rect(bounds, wh, wh);
   1344     setup_style(op, rect);
   1345     _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h);
   1346   }
   1347 }
   1348 
   1349 void AggModule::render_rect_rotated(RenderOp op) {
   1350   BLSize bounds(_params.screen_w, _params.screen_h);
   1351   StyleKind style = _params.style;
   1352 
   1353   double cx = double(_params.screen_w) * 0.5;
   1354   double cy = double(_params.screen_h) * 0.5;
   1355   double wh = _params.shape_size;
   1356   double angle = 0.0;
   1357 
   1358   prepare_fill_stroke_option(op);
   1359 
   1360   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
   1361     BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
   1362 
   1363     agg::trans_affine affine;
   1364     affine.translate(-cx, -cy);
   1365     affine.rotate(angle);
   1366     affine.translate(cx, cy);
   1367 
   1368     _ctx.affine(affine);
   1369     setup_style(op, rect);
   1370     _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h);
   1371     _ctx.resetTransformations();
   1372   }
   1373 }
   1374 
   1375 void AggModule::render_round_f(RenderOp op) {
   1376   BLSize bounds(_params.screen_w, _params.screen_h);
   1377   StyleKind style = _params.style;
   1378   double wh = _params.shape_size;
   1379 
   1380   prepare_fill_stroke_option(op);
   1381 
   1382   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1383     BLRect rect = _rnd_coord.next_rect(bounds, wh, wh);
   1384     double radius = _rnd_extra.next_double(4.0, 40.0);
   1385 
   1386     setup_style(op, rect);
   1387     _ctx.roundedRect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, radius);
   1388   }
   1389 }
   1390 
   1391 void AggModule::render_round_rotated(RenderOp op) {
   1392   BLSize bounds(_params.screen_w, _params.screen_h);
   1393   StyleKind style = _params.style;
   1394 
   1395   double cx = double(_params.screen_w) * 0.5;
   1396   double cy = double(_params.screen_h) * 0.5;
   1397   double wh = _params.shape_size;
   1398   double angle = 0.0;
   1399 
   1400   prepare_fill_stroke_option(op);
   1401 
   1402   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
   1403     BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
   1404     double radius = _rnd_extra.next_double(4.0, 40.0);
   1405 
   1406     agg::trans_affine affine;
   1407     affine.translate(-cx, -cy);
   1408     affine.rotate(angle);
   1409     affine.translate(cx, cy);
   1410     _ctx.affine(affine);
   1411 
   1412     setup_style(op, rect);
   1413     _ctx.roundedRect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, radius);
   1414     _ctx.resetTransformations();
   1415   }
   1416 }
   1417 
   1418 void AggModule::render_polygon(RenderOp op, uint32_t complexity) {
   1419   BLSizeI bounds(_params.screen_w - _params.shape_size,
   1420                  _params.screen_h - _params.shape_size);
   1421 
   1422   StyleKind style = _params.style;
   1423   double wh = _params.shape_size;
   1424 
   1425   prepare_fill_stroke_option(op);
   1426   _ctx.fillEvenOdd(op == RenderOp::kFillEvenOdd);
   1427 
   1428   Agg2D::DrawPathFlag draw_path_flag = op == RenderOp::kStroke ? Agg2D::StrokeOnly : Agg2D::FillOnly;
   1429 
   1430   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1431     BLPoint base(_rnd_coord.nextPoint(bounds));
   1432 
   1433     double x = _rnd_coord.next_double(base.x, base.x + wh);
   1434     double y = _rnd_coord.next_double(base.y, base.y + wh);
   1435 
   1436     _ctx.resetPath();
   1437     _ctx.moveTo(x, y);
   1438 
   1439     for (uint32_t p = 1; p < complexity; p++) {
   1440       x = _rnd_coord.next_double(base.x, base.x + wh);
   1441       y = _rnd_coord.next_double(base.y, base.y + wh);
   1442       _ctx.lineTo(x, y);
   1443     }
   1444 
   1445     setup_style(op, BLRect(base.x, base.y, wh, wh));
   1446     _ctx.drawPath(draw_path_flag);
   1447   }
   1448 }
   1449 
   1450 void AggModule::render_shape(RenderOp op, ShapeData shape) {
   1451   BLSizeI bounds(_params.screen_w - _params.shape_size,
   1452                  _params.screen_h - _params.shape_size);
   1453 
   1454   StyleKind style = _params.style;
   1455   double wh = double(_params.shape_size);
   1456 
   1457   prepare_fill_stroke_option(op);
   1458   _ctx.fillEvenOdd(op == RenderOp::kFillEvenOdd);
   1459 
   1460   Agg2D::DrawPathFlag draw_path_flag = op == RenderOp::kStroke ? Agg2D::StrokeOnly : Agg2D::FillOnly;
   1461 
   1462   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
   1463     BLPoint base(_rnd_coord.nextPoint(bounds));
   1464     ShapeIterator it(shape);
   1465 
   1466     _ctx.resetPath();
   1467     while (it.has_command()) {
   1468       if (it.is_move_to()) {
   1469         _ctx.moveTo(base.x + it.x(0) * wh, base.y + it.y(0) * wh);
   1470       }
   1471       else if (it.is_line_to()) {
   1472         _ctx.lineTo(base.x + it.x(0) * wh, base.y + it.y(0) * wh);
   1473       }
   1474       else if (it.is_quad_to()) {
   1475         _ctx.quadricCurveTo(
   1476           base.x + it.x(0) * wh, base.y + it.y(0) * wh,
   1477           base.x + it.x(1) * wh, base.y + it.y(1) * wh
   1478         );
   1479       }
   1480       else if (it.is_cubic_to()) {
   1481         _ctx.cubicCurveTo(
   1482           base.x + it.x(0) * wh, base.y + it.y(0) * wh,
   1483           base.x + it.x(1) * wh, base.y + it.y(1) * wh,
   1484           base.x + it.x(2) * wh, base.y + it.y(2) * wh
   1485         );
   1486       }
   1487       else {
   1488         _ctx.closePolygon();
   1489       }
   1490       it.next();
   1491     }
   1492 
   1493     setup_style(op, BLRect(base.x, base.y, wh, wh));
   1494     _ctx.drawPath(draw_path_flag);
   1495   }
   1496 }
   1497 
   1498 Backend* create_agg_backend() {
   1499   return new AggModule();
   1500 }
   1501 
   1502 } // {blbench}
   1503 
   1504 #endif // BL_BENCH_ENABLE_AGG