context2d.cpp Example File
					 
					
						script/context2d/context2d.cpp
					 
					
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/ 
#include "context2d.h" 
#include <QVariant> 
#include <qmath.h> 
#define qClamp(val, min, max) qMin(qMax(val, min), max) 
static  QList < qreal >  parseNumbersList(QString :: const_iterator & itr)
{
    QList < qreal >  points;
    QString while  ((* itr). isSpace())
        + + itr;
    while  ((* itr). isNumber() | | 
           (* itr) = =  '-'  | |  (* itr) = =  '+'  | |  (* itr) = =  '.' ) {
        temp =  QString if  ((* itr) = =  '-' )
            temp + =  * itr+ + ;
        else  if  ((* itr) = =  '+' )
            temp + =  * itr+ + ;
        while  ((* itr). isDigit())
            temp + =  * itr+ + ;
        if  ((* itr) = =  '.' )
            temp + =  * itr+ + ;
        while  ((* itr). isDigit())
            temp + =  * itr+ + ;
        while  ((* itr). isSpace())
            + + itr;
        if  ((* itr) = =  ',' )
            + + itr;
        points. append(temp. toDouble());
        //eat spaces 
        while  ((* itr). isSpace())
            + + itr;
    }
    return  points;
}
QColor  colorFromString(const  QString & name)
{
    QString :: const_iterator itr =  name. constBegin();
    QList < qreal >  compo;
    if  (name. startsWith("rgba(" )) {
        + + itr; + + itr; + + itr; + + itr; + + itr;
        compo =  parseNumbersList(itr);
        if  (compo. size() ! =  4 ) {
            return  QColor ();
        }
        //alpha seems to be always between 0-1 
        compo[ 3 ]  * =  255 ;
        return  QColor ((int )compo[ 0 ] ,  (int )compo[ 1 ] , 
                      (int )compo[ 2 ] ,  (int )compo[ 3 ] );
    } else  if  (name. startsWith("rgb(" )) {
        + + itr; + + itr; + + itr; + + itr;
        compo =  parseNumbersList(itr);
        if  (compo. size() ! =  3 ) {
            return  QColor ();
        }
        return  QColor ((int )qClamp(compo[ 0 ] ,  qreal 0 ),  qreal 255 )), 
                      (int )qClamp(compo[ 1 ] ,  qreal 0 ),  qreal 255 )), 
                      (int )qClamp(compo[ 2 ] ,  qreal 0 ),  qreal 255 )));
    } else  {
        //QRgb color; 
        //CSSParser::parseColor(name, color); 
        return  QColor (name);
    }
}
static  QPainter :: CompositionMode compositeOperatorFromString(const  QString & compositeOperator)
{
    if  ( compositeOperator = =  "source-over"  ) {
        return  QPainter :: CompositionMode_SourceOver;
    } else  if  ( compositeOperator = =  "source-out"  ) {
        return  QPainter :: CompositionMode_SourceOut;
    } else  if  ( compositeOperator = =  "source-in"  ) {
        return  QPainter :: CompositionMode_SourceIn;
    } else  if  ( compositeOperator = =  "source-atop"  ) {
        return  QPainter :: CompositionMode_SourceAtop;
    } else  if  ( compositeOperator = =  "destination-atop"  ) {
        return  QPainter :: CompositionMode_DestinationAtop;
    } else  if  ( compositeOperator = =  "destination-in"  ) {
        return  QPainter :: CompositionMode_DestinationIn;
    } else  if  ( compositeOperator = =  "destination-out"  ) {
        return  QPainter :: CompositionMode_DestinationOut;
    } else  if  ( compositeOperator = =  "destination-over"  ) {
        return  QPainter :: CompositionMode_DestinationOver;
    } else  if  ( compositeOperator = =  "darker"  ) {
        return  QPainter :: CompositionMode_SourceOver;
    } else  if  ( compositeOperator = =  "lighter"  ) {
        return  QPainter :: CompositionMode_SourceOver;
    } else  if  ( compositeOperator = =  "copy"  ) {
        return  QPainter :: CompositionMode_Source;
    } else  if  ( compositeOperator = =  "xor"  ) {
        return  QPainter :: CompositionMode_Xor;
    }
    return  QPainter :: CompositionMode_SourceOver;
}
static  QString QPainter :: CompositionMode op)
{
    switch  (op) {
    case  QPainter :: CompositionMode_SourceOver:
        return  "source-over" ;
    case  QPainter :: CompositionMode_DestinationOver:
        return  "destination-over" ;
    case  QPainter :: CompositionMode_Clear:
        return  "clear" ;
    case  QPainter :: CompositionMode_Source:
        return  "source" ;
    case  QPainter :: CompositionMode_Destination:
        return  "destination" ;
    case  QPainter :: CompositionMode_SourceIn:
        return  "source-in" ;
    case  QPainter :: CompositionMode_DestinationIn:
        return  "destination-in" ;
    case  QPainter :: CompositionMode_SourceOut:
        return  "source-out" ;
    case  QPainter :: CompositionMode_DestinationOut:
        return  "destination-out" ;
    case  QPainter :: CompositionMode_SourceAtop:
        return  "source-atop" ;
    case  QPainter :: CompositionMode_DestinationAtop:
        return  "destination-atop" ;
    case  QPainter :: CompositionMode_Xor:
        return  "xor" ;
    case  QPainter :: CompositionMode_Plus:
        return  "plus" ;
    case  QPainter :: CompositionMode_Multiply:
        return  "multiply" ;
    case  QPainter :: CompositionMode_Screen:
        return  "screen" ;
    case  QPainter :: CompositionMode_Overlay:
        return  "overlay" ;
    case  QPainter :: CompositionMode_Darken:
        return  "darken" ;
    case  QPainter :: CompositionMode_Lighten:
        return  "lighten" ;
    case  QPainter :: CompositionMode_ColorDodge:
        return  "color-dodge" ;
    case  QPainter :: CompositionMode_ColorBurn:
        return  "color-burn" ;
    case  QPainter :: CompositionMode_HardLight:
        return  "hard-light" ;
    case  QPainter :: CompositionMode_SoftLight:
        return  "soft-light" ;
    case  QPainter :: CompositionMode_Difference:
        return  "difference" ;
    case  QPainter :: CompositionMode_Exclusion:
        return  "exclusion" ;
    default :
        break ;
    }
    return  QString void  Context2D:: save()
{
    m_stateStack. push(m_state);
}
void  Context2D:: restore()
{
    if  (! m_stateStack. isEmpty()) {
        m_state =  m_stateStack. pop();
        m_state. flags =  AllIsFullOfDirt;
    }
}
void  Context2D:: scale(qreal ,  qreal . matrix. scale(x,  y);
    m_state. flags | =  DirtyTransformationMatrix;
}
void  Context2D:: rotate(qreal . matrix. rotate(qRadiansToDegrees (angle));
    m_state. flags | =  DirtyTransformationMatrix;
}
void  Context2D:: translate(qreal ,  qreal . matrix. translate(x,  y);
    m_state. flags | =  DirtyTransformationMatrix;
}
void  Context2D:: transform(qreal ,  qreal ,  qreal ,  qreal , 
                          qreal ,  qreal QMatrix  mat(m11,  m12, 
                m21,  m22, 
                dx,  dy);
    m_state. matrix * =  mat;
    m_state. flags | =  DirtyTransformationMatrix;
}
void  Context2D:: setTransform(qreal ,  qreal ,  qreal ,  qreal , 
                             qreal ,  qreal QMatrix  mat(m11,  m12, 
                m21,  m22, 
                dx,  dy);
    m_state. matrix =  mat;
    m_state. flags | =  DirtyTransformationMatrix;
}
QString :: globalCompositeOperation() const 
{
    return  compositeOperatorToString(m_state. globalCompositeOperation);
}
void  Context2D:: setGlobalCompositeOperation(const  QString & op)
{
    QPainter :: CompositionMode mode = 
        compositeOperatorFromString(op);
    m_state. globalCompositeOperation =  mode;
    m_state. flags | =  DirtyGlobalCompositeOperation;
}
QVariant :: strokeStyle() const 
{
    return  m_state. strokeStyle;
}
void  Context2D:: setStrokeStyle(const  QVariant & style)
{
    if  (style. canConvert< CanvasGradient> ()) {
        CanvasGradient cg =  qvariant_cast< CanvasGradient> (style);
        m_state. strokeStyle =  cg. value;
    } else  {
        QColor  color =  colorFromString(style. toString());
        m_state. strokeStyle =  color;
    }
    m_state. flags | =  DirtyStrokeStyle;
}
QVariant :: fillStyle() const 
{
    return  m_state. fillStyle;
}
void  Context2D:: setFillStyle(const  QVariant & style)
{
    if  (style. canConvert< CanvasGradient> ()) {
        CanvasGradient cg =  qvariant_cast< CanvasGradient> (style);
        m_state. fillStyle =  cg. value;
    } else  {
        QColor  color =  colorFromString(style. toString());
        m_state. fillStyle =  color;
    }
    m_state. flags | =  DirtyFillStyle;
}
qreal :: globalAlpha() const 
{
    return  m_state. globalAlpha;
}
void  Context2D:: setGlobalAlpha(qreal . globalAlpha =  alpha;
    m_state. flags | =  DirtyGlobalAlpha;
}
CanvasGradient Context2D:: createLinearGradient(qreal ,  qreal , 
                                               qreal ,  qreal QLinearGradient  g(x0,  y0,  x1,  y1);
    return  CanvasGradient(g);
}
CanvasGradient Context2D:: createRadialGradient(qreal ,  qreal , 
                                               qreal ,  qreal , 
                                               qreal ,  qreal QRadialGradient  g(QPointF ,  y1),  r0+ r1,  QPointF ,  y0));
    return  CanvasGradient(g);
}
qreal :: lineWidth() const 
{
    return  m_state. lineWidth;
}
void  Context2D:: setLineWidth(qreal . lineWidth =  w;
    m_state. flags | =  DirtyLineWidth;
}
QString :: lineCap() const 
{
    switch  (m_state. lineCap) {
    case  Qt :: FlatCap:
        return  "butt" ;
    case  Qt :: SquareCap:
        return  "square" ;
    case  Qt :: RoundCap:
        return  "round" ;
    default : ;
    }
    return  QString void  Context2D:: setLineCap(const  QString & capString)
{
    Qt :: PenCapStyle style;
    if  (capString = =  "round" )
        style =  Qt :: RoundCap;
    else  if  (capString = =  "square" )
        style =  Qt :: SquareCap;
    else  //if (capString == "butt") 
        style =  Qt :: FlatCap;
    m_state. lineCap =  style;
    m_state. flags | =  DirtyLineCap;
}
QString :: lineJoin() const 
{
    switch  (m_state. lineJoin) {
    case  Qt :: RoundJoin:
        return  "round" ;
    case  Qt :: BevelJoin:
        return  "bevel" ;
    case  Qt :: MiterJoin:
        return  "miter" ;
    default : ;
    }
    return  QString void  Context2D:: setLineJoin(const  QString & joinString)
{
    Qt :: PenJoinStyle style;
    if  (joinString = =  "round" )
        style =  Qt :: RoundJoin;
    else  if  (joinString = =  "bevel" )
        style =  Qt :: BevelJoin;
    else  //if (joinString == "miter") 
        style =  Qt :: MiterJoin;
    m_state. lineJoin =  style;
    m_state. flags | =  DirtyLineJoin;
}
qreal :: miterLimit() const 
{
    return  m_state. miterLimit;
}
void  Context2D:: setMiterLimit(qreal . miterLimit =  m;
    m_state. flags | =  DirtyMiterLimit;
}
void  Context2D:: setShadowOffsetX(qreal . shadowOffsetX =  x;
    m_state. flags | =  DirtyShadowOffsetX;
}
void  Context2D:: setShadowOffsetY(qreal . shadowOffsetY =  y;
    m_state. flags | =  DirtyShadowOffsetY;
}
void  Context2D:: setShadowBlur(qreal . shadowBlur =  b;
    m_state. flags | =  DirtyShadowBlur;
}
void  Context2D:: setShadowColor(const  QString & str)
{
    m_state. shadowColor =  colorFromString(str);
    m_state. flags | =  DirtyShadowColor;
}
qreal :: shadowOffsetX() const 
{
    return  m_state. shadowOffsetX;
}
qreal :: shadowOffsetY() const 
{
    return  m_state. shadowOffsetY;
}
qreal :: shadowBlur() const 
{
    return  m_state. shadowBlur;
}
QString :: shadowColor() const 
{
    return  m_state. shadowColor. name();
}
void  Context2D:: clearRect(qreal ,  qreal ,  qreal ,  qreal . save();
    m_painter. setMatrix(m_state. matrix,  false );
    m_painter. setCompositionMode(QPainter :: CompositionMode_Source);
    m_painter. fillRect(QRectF ,  y,  w,  h),  QColor (0 ,  0 ,  0 ,  0 ));
    m_painter. restore();
    scheduleChange();
}
void  Context2D:: fillRect(qreal ,  qreal ,  qreal ,  qreal . save();
    m_painter. setMatrix(m_state. matrix,  false );
    m_painter. fillRect(QRectF ,  y,  w,  h),  m_painter. brush());
    m_painter. restore();
    scheduleChange();
}
void  Context2D:: strokeRect(qreal ,  qreal ,  qreal ,  qreal QPainterPath  path;
    path. addRect(x,  y,  w,  h);
    beginPainting();
    m_painter. save();
    m_painter. setMatrix(m_state. matrix,  false );
    m_painter. strokePath(path,  m_painter. pen());
    m_painter. restore();
    scheduleChange();
}
void  Context2D:: beginPath()
{
    m_path =  QPainterPath ();
}
void  Context2D:: closePath()
{
    m_path. closeSubpath();
}
void  Context2D:: moveTo(qreal ,  qreal QPointF =  m_state. matrix. map(QPointF ,  y));
    m_path. moveTo(pt);
}
void  Context2D:: lineTo(qreal ,  qreal QPointF =  m_state. matrix. map(QPointF ,  y));
    m_path. lineTo(pt);
}
void  Context2D:: quadraticCurveTo(qreal ,  qreal ,  qreal ,  qreal QPointF =  m_state. matrix. map(QPointF ,  cpy));
    QPointF =  m_state. matrix. map(QPointF ,  y));
    m_path. quadTo(cp,  xy);
}
void  Context2D:: bezierCurveTo(qreal ,  qreal , 
                              qreal ,  qreal ,  qreal ,  qreal QPointF =  m_state. matrix. map(QPointF ,  cp1y));
    QPointF =  m_state. matrix. map(QPointF ,  cp2y));
    QPointF =  m_state. matrix. map(QPointF ,  y));
    m_path. cubicTo(cp1,  cp2,  end);
}
void  Context2D:: arcTo(qreal ,  qreal ,  qreal ,  qreal ,  qreal //FIXME: this is surely busted 
    QPointF =  m_state. matrix. map(QPointF ,  y1));
    QPointF =  m_state. matrix. map(QPointF ,  y2));
    m_path. arcTo(st. x(),  st. y(), 
                 end. x()- st. x(),  end. y()- st. y(), 
                 radius,  90 );
}
void  Context2D:: rect(qreal ,  qreal ,  qreal ,  qreal QPainterPath  path; path. addRect(x,  y,  w,  h);
    path =  m_state. matrix. map(path);
    m_path. addPath(path);
}
void  Context2D:: arc(qreal ,  qreal ,  qreal , 
                    qreal ,  qreal , 
                    bool anticlockwise)
{
    //### HACK 
    // In Qt we don't switch the coordinate system for degrees 
    // and still use the 0,0 as bottom left for degrees so we need 
    // to switch 
    sar =  - sar;
    ear =  - ear;
    anticlockwise =  ! anticlockwise;
    //end hack 
    float  sa =  qRadiansToDegrees (sar);
    float  ea =  qRadiansToDegrees (ear);
    double  span =  0 ;
    double  xs     =  xc -  radius;
    double  ys     =  yc -  radius;
    double  width  =  radius* 2 ;
    double  height =  radius* 2 ;
    if  (! anticlockwise & &  (ea <  sa)) {
        span + =  360 ;
    } else  if  (anticlockwise & &  (sa <  ea)) {
        span - =  360 ;
    }
    //### this is also due to switched coordinate system 
    // we would end up with a 0 span instead of 360 
    if  (! (qFuzzyCompare (span +  (ea -  sa) +  1 ,  1 ) & & 
          qFuzzyCompare (qAbs (span),  360 ))) {
        span   + =  ea -  sa;
    }
    QPainterPath  path;
    path. moveTo(QPointF +  radius  *  cos(sar), 
                                yc -  radius  *  sin(sar)));
    path. arcTo(xs,  ys,  width,  height,  sa,  span);
    path =  m_state. matrix. map(path);
    m_path. addPath(path);
}
void  Context2D:: fill()
{
    beginPainting();
    m_painter. fillPath(m_path,  m_painter. brush());
    scheduleChange();
}
void  Context2D:: stroke()
{
    beginPainting();
    m_painter. save();
    m_painter. setMatrix(m_state. matrix,  false );
    QPainterPath  tmp =  m_state. matrix. inverted(). map(m_path);
    m_painter. strokePath(tmp,  m_painter. pen());
    m_painter. restore();
    scheduleChange();
}
void  Context2D:: clip()
{
    m_state. clipPath =  m_path;
    m_state. flags | =  DirtyClippingRegion;
}
bool Context2D:: isPointInPath(qreal ,  qreal const 
{
    return  m_path. contains(QPointF ,  y));
}
ImageData Context2D:: getImageData(qreal ,  qreal ,  qreal ,  qreal return  ImageData();
}
void  Context2D:: putImageData(ImageData image,  qreal ,  qreal :: Context2D(QObject * parent)
    : QObject ,  m_changeTimerId(- 1 )
{
    reset();
}
const  QImage  & Context2D:: endPainting()
{
    if  (m_painter. isActive())
        m_painter. end();
    return  m_image;
}
void  Context2D:: beginPainting()
{
    if  (! m_painter. isActive()) {
        m_painter. begin(& m_image);
        m_painter. setRenderHint(QPainter :: Antialiasing);
        if  (! m_state. clipPath. isEmpty())
            m_painter. setClipPath(m_state. clipPath);
        m_painter. setBrush(m_state. fillStyle);
        m_painter. setOpacity(m_state. globalAlpha);
        QPen  pen;
        pen. setBrush(m_state. strokeStyle);
        if  (pen. style() = =  Qt :: NoPen)
            pen. setStyle(Qt :: SolidLine);
        pen. setCapStyle(m_state. lineCap);
        pen. setJoinStyle(m_state. lineJoin);
        pen. setWidthF(m_state. lineWidth);
        pen. setMiterLimit(m_state. miterLimit);
        m_painter. setPen(pen);
    } else  {
        if  ((m_state. flags &  DirtyClippingRegion) & &  ! m_state. clipPath. isEmpty())
            m_painter. setClipPath(m_state. clipPath);
        if  (m_state. flags &  DirtyFillStyle)
            m_painter. setBrush(m_state. fillStyle);
        if  (m_state. flags &  DirtyGlobalAlpha)
            m_painter. setOpacity(m_state. globalAlpha);
        if  (m_state. flags &  DirtyGlobalCompositeOperation)
            m_painter. setCompositionMode(m_state. globalCompositeOperation);
        if  (m_state. flags &  MDirtyPen) {
            QPen  pen =  m_painter. pen();
            if  (m_state. flags &  DirtyStrokeStyle)
                pen. setBrush(m_state. strokeStyle);
            if  (m_state. flags &  DirtyLineWidth)
                pen. setWidthF(m_state. lineWidth);
            if  (m_state. flags &  DirtyLineCap)
                pen. setCapStyle(m_state. lineCap);
            if  (m_state. flags &  DirtyLineJoin)
                pen. setJoinStyle(m_state. lineJoin);
            if  (m_state. flags &  DirtyMiterLimit)
                pen. setMiterLimit(m_state. miterLimit);
            m_painter. setPen(pen);
        }
        m_state. flags =  0 ;
    }
}
void  Context2D:: clear()
{
    endPainting();
    m_image. fill(qRgba(0 , 0 , 0 , 0 ));
    scheduleChange();
}
void  Context2D:: reset()
{
    m_stateStack. clear();
    m_state. matrix =  QMatrix ();
    m_state. clipPath =  QPainterPath ();
    m_state. globalAlpha =  1.0 ;
    m_state. globalCompositeOperation =  QPainter :: CompositionMode_SourceOver;
    m_state. strokeStyle =  Qt :: black;
    m_state. fillStyle =  Qt :: black;
    m_state. lineWidth =  1 ;
    m_state. lineCap =  Qt :: FlatCap;
    m_state. lineJoin =  Qt :: MiterJoin;
    m_state. miterLimit =  10 ;
    m_state. shadowOffsetX =  0 ;
    m_state. shadowOffsetY =  0 ;
    m_state. shadowBlur =  0 ;
    m_state. shadowColor =  qRgba(0 ,  0 ,  0 ,  0 );
    m_state. flags =  AllIsFullOfDirt;
    clear();
}
void  Context2D:: setSize(int  width,  int  height)
{
    endPainting();
    QImage  newi(width,  height,  QImage :: Format_ARGB32_Premultiplied);
    newi. fill(qRgba(0 , 0 , 0 , 0 ));
    QPainter  p(& newi);
    p. drawImage(0 ,  0 ,  m_image);
    p. end();
    m_image =  newi;
    scheduleChange();
}
void  Context2D:: setSize(const  QSize & size)
{
    setSize(size. width(),  size. height());
}
QSize :: size() const 
{
    return  m_image. size();
}
void  Context2D:: drawImage(DomImage * image,  qreal ,  qreal if  (! image)
        return ;
    if  (dx <  0 ) {
        qreal =  qAbs (dx);
        qreal =  qAbs (dy);
        qreal =  image- > width() -  sx;
        qreal =  image- > height() -  sy;
        drawImage(image,  sx,  sy,  sw,  sh,  0 ,  0 ,  sw,  sh);
    } else  {
        beginPainting();
        m_painter. drawImage(QPointF ,  dy),  image- > image());
        scheduleChange();
    }
}
void  Context2D:: drawImage(DomImage * image,  qreal ,  qreal , 
                          qreal ,  qreal if  (! image)
        return ;
    beginPainting();
    m_painter. drawImage(QRectF ,  dy,  dw,  dh). toRect(),  image- > image());
    scheduleChange();
}
void  Context2D:: drawImage(DomImage * image,  qreal ,  qreal , 
                          qreal ,  qreal ,  qreal ,  qreal , 
                          qreal ,  qreal if  (! image)
        return ;
    beginPainting();
    m_painter. drawImage(QRectF ,  dy,  dw,  dh),  image- > image(), 
                        QRectF ,  sy,  sw,  sh));
    scheduleChange();
}
void  Context2D:: scheduleChange()
{
    if  (m_changeTimerId = =  - 1 )
        m_changeTimerId =  startTimer(0 );
}
void  Context2D:: timerEvent(QTimerEvent * e)
{
    if  (e- > timerId() = =  m_changeTimerId) {
        killTimer(m_changeTimerId);
        m_changeTimerId =  - 1 ;
        emit  changed(endPainting());
    } else  {
        QObject :: timerEvent(e);
    }
}