]> git.saurik.com Git - wxWidgets.git/blobdiff - contrib/src/canvas/canvas.cpp
First draft of a cygwin script to create wxMSW distributions
[wxWidgets.git] / contrib / src / canvas / canvas.cpp
index f2284c9ed751818e489a982eaeb651f8c14b9999..1be997526aeec5e68ea0b5e059ec75b7cbc43444 100644 (file)
@@ -77,7 +77,7 @@ void wxCanvasObject::Move( int x, int y )
 {
     int old_x = m_area.x;
     int old_y = m_area.y;
-    
+
     m_area.x = x;
     m_area.y = y;
 
@@ -153,7 +153,7 @@ void wxCanvasObjectGroup::SetOwner(wxCanvas* canvas)
     }
 }
 
-void wxCanvasObjectGroup::ExtendArea(int x, int y)
+void wxCanvasObjectGroup::ExtendArea(double x, double y)
 {
     if (m_validbounds)
     {
@@ -284,12 +284,12 @@ bool wxCanvasObjectGroup::IsHit( int x, int y, int margin )
         {
             if (obj->IsHit(x,y,margin))
             {
-                return true;
+                return TRUE;
             }
         }
         node = node->Previous();
     }
-    return false;
+    return FALSE;
 }
 
 wxCanvasObject* wxCanvasObjectGroup::IsHitObject( int x, int y, int margin )
@@ -309,7 +309,7 @@ wxCanvasObject* wxCanvasObjectGroup::IsHitObject( int x, int y, int margin )
         }
         node = node->Previous();
     }
-    
+
     return (wxCanvasObject*) NULL;
 }
 
@@ -322,40 +322,39 @@ wxCanvasObjectGroupRef::wxCanvasObjectGroupRef(double x, double y, wxCanvasObjec
 {
     m_x = x;
     m_y = y;
-    m_validbounds=false;
-    m_group=group;
+    m_validbounds = FALSE;
+    m_group = group;
 }
 
 void wxCanvasObjectGroupRef::SetOwner(wxCanvas* canvas)
 {
-    m_owner=canvas;
+    m_owner = canvas;
     m_group->SetOwner(canvas);
 }
 
-void wxCanvasObjectGroupRef::ExtendArea(int x, int y)
+void wxCanvasObjectGroupRef::ExtendArea(double x, double y)
 {
-   if (m_validbounds)
-   {
-     if ( x < m_minx ) m_minx = x;
-     if ( y < m_miny ) m_miny = y;
-     if ( x > m_maxx ) m_maxx = x;
-     if ( y > m_maxy ) m_maxy = y;
-   }
-   else
-   {
-      m_validbounds = true;
-
-      m_minx = x;
-      m_miny = y;
-      m_maxx = x;
-      m_maxy = y;
-   }
+    if (m_validbounds)
+    {
+        if (x < m_minx) m_minx = x;
+        if (y < m_miny) m_miny = y;
+        if (x > m_maxx) m_maxx = x;
+        if (y > m_maxy) m_maxy = y;
+    }
+    else
+    {
+        m_validbounds = TRUE;
 
+        m_minx = x;
+        m_miny = y;
+        m_maxx = x;
+        m_maxy = y;
+    }
 }
 
 void wxCanvasObjectGroupRef::Recreate()
 {
-    m_validbounds=false;
+    m_validbounds = FALSE;
     m_group->Recreate();
     ExtendArea(m_group->GetXMin(),m_group->GetYMin());
     ExtendArea(m_group->GetXMax(),m_group->GetYMax());
@@ -369,8 +368,8 @@ void wxCanvasObjectGroupRef::Recreate()
 
 void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width, int height )
 {
-    xabs += m_owner->GetDeviceX(GetPosX());
-    yabs += m_owner->GetDeviceY(GetPosY());
+    xabs += m_area.x;
+    yabs += m_area.y;
 
     int clip_x = xabs + m_group->GetXMin();
     int clip_width = m_group->GetXMax()-m_group->GetXMin();
@@ -424,27 +423,223 @@ void wxCanvasObjectGroupRef::Move( int x, int y )
     m_x = x;
     m_y = y;
 
-    if (!m_isControl)
+    int old_area_x = m_area.x;
+    int old_area_y = m_area.y;
+
+    m_area.x=m_owner->GetDeviceX(  m_x + m_minx );
+    m_area.y=m_owner->GetDeviceY(  m_y + m_miny );
+
+       int leftu,rightu,bottomu,topu ;
+       leftu   = wxMin (m_area.x, old_area_x ) ;
+       rightu  = wxMax (old_area_x + m_area.width, m_area.x + m_area.width) ;
+       topu    = wxMin (m_area.y,old_area_y) ;
+       bottomu = wxMax (old_area_y + m_area.height, m_area.y + m_area.height) ;
+
+    if ( rightu - leftu < 2*m_area.width && bottomu - topu < 2*m_area.height )
     {
-        // TODO: sometimes faster to merge into 1 Update or
-        // to break up into four
-        m_owner->Update(m_area.x, m_area.y, m_area.width, m_area.height );
-        //calculate the new area in pixels relative to the parent
-        SetArea( m_owner->GetDeviceX(  m_x + m_minx ),
-                 m_owner->GetDeviceY(  m_y + m_miny ),
-                 m_owner->GetDeviceWidth( m_maxx-m_minx ),
-                 m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+        m_owner->Update(leftu,topu,rightu - leftu,bottomu - topu);
+    }
+    else
+    {
+        m_owner->Update(old_area_x, old_area_y, m_area.width, m_area.height );
         m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height );
     }
 }
 
+//----------------------------------------------------------------------------
+// wxCanvasPolyline
+//----------------------------------------------------------------------------
+
+wxCanvasPolyline::wxCanvasPolyline( int n,  wxPoint2DDouble points[])
+   : wxCanvasObject()
+{
+    m_n = n;
+    m_points = points;
+    m_pen = *wxBLACK_PEN;
+}
+
+wxCanvasPolyline::~wxCanvasPolyline()
+{
+    delete m_points;
+}
+
+void wxCanvasPolyline::ExtendArea(double x, double y)
+{
+    if (m_validbounds)
+    {
+        if (x < m_minx) m_minx = x;
+        if (y < m_miny) m_miny = y;
+        if (x > m_maxx) m_maxx = x;
+        if (y > m_maxy) m_maxy = y;
+    }
+    else
+    {
+        m_validbounds = TRUE;
+
+        m_minx = x;
+        m_miny = y;
+        m_maxx = x;
+        m_maxy = y;
+    }
+}
+
+void wxCanvasPolyline::Recreate()
+{
+
+    m_validbounds=FALSE;
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        ExtendArea(m_points[i].m_x,m_points[i].m_y);
+    }
+
+    //include the pen width also
+    ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
+    ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
+
+    //set the area in pixels relative to the parent
+    SetArea( m_owner->GetDeviceX(m_minx ),
+             m_owner->GetDeviceY(m_miny ),
+             m_owner->GetDeviceWidth( m_maxx-m_minx ),
+             m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+}
+
+void wxCanvasPolyline::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    int buffer_x = m_owner->GetBufferX();
+    int buffer_y = m_owner->GetBufferY();
+
+    int start_y = clip_y - buffer_y;
+    int end_y = clip_y+clip_height - buffer_y;
+
+    int start_x = clip_x - buffer_x;
+    int end_x = clip_x+clip_width - buffer_x;
+
+#if IMAGE_CANVAS
+#else
+    wxPoint *cpoints = new wxPoint[m_n];
+    int i;
+    for (i = 0; i < m_n; i++)
+    {
+        cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
+        cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
+    }
+    wxMemoryDC *dc = m_owner->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    dc->SetPen(m_pen);
+    dc->DrawLines(m_n, cpoints, 0,0);
+    delete [] cpoints;
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+#endif
+}
+
+void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+//----------------------------------------------------------------------------
+// wxCanvasPolygon
+//----------------------------------------------------------------------------
+
+wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[])
+   : wxCanvasObject()
+{
+    m_n = n;
+    m_points = points;
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
+}
+
+wxCanvasPolygon::~wxCanvasPolygon()
+{
+    delete m_points;
+}
+
+void wxCanvasPolygon::ExtendArea(double x, double y)
+{
+    if (m_validbounds)
+    {
+        if (x < m_minx) m_minx = x;
+        if (y < m_miny) m_miny = y;
+        if (x > m_maxx) m_maxx = x;
+        if (y > m_maxy) m_maxy = y;
+    }
+    else
+    {
+        m_validbounds = TRUE;
+
+        m_minx = x;
+        m_miny = y;
+        m_maxx = x;
+        m_maxy = y;
+    }
+}
+
+void wxCanvasPolygon::Recreate()
+{
+
+    m_validbounds=FALSE;
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        ExtendArea(m_points[i].m_x,m_points[i].m_y);
+    }
+
+    //include the pen width also
+    ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
+    ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
+
+    //set the area in pixels relative to the parent
+    SetArea( m_owner->GetDeviceX( m_minx ),
+             m_owner->GetDeviceY( m_miny ),
+             m_owner->GetDeviceWidth( m_maxx-m_minx ),
+             m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+}
+
+void wxCanvasPolygon::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    int buffer_x = m_owner->GetBufferX();
+    int buffer_y = m_owner->GetBufferY();
+
+    int start_y = clip_y - buffer_y;
+    int end_y = clip_y+clip_height - buffer_y;
+
+    int start_x = clip_x - buffer_x;
+    int end_x = clip_x+clip_width - buffer_x;
+
+#if IMAGE_CANVAS
+#else
+    wxPoint *cpoints = new wxPoint[m_n];
+    int i;
+    for (i = 0; i < m_n; i++)
+    {
+        cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
+        cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
+    }
+    wxMemoryDC *dc = m_owner->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    dc->SetBrush(m_brush);
+    dc->SetPen(m_pen);
+    dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
+    delete [] cpoints;
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+#endif
+}
+
+void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+
 
 //----------------------------------------------------------------------------
 // wxCanvasRect
 //----------------------------------------------------------------------------
 
-wxCanvasRect::wxCanvasRect( double x, double y, double w, double h,
-                            unsigned char red, unsigned char green, unsigned char blue )
+wxCanvasRect::wxCanvasRect( double x, double y, double w, double h )
    : wxCanvasObject()
 {
     m_x = x;
@@ -452,9 +647,8 @@ wxCanvasRect::wxCanvasRect( double x, double y, double w, double h,
     m_width = w;
     m_height = h;
 
-    m_red = red;
-    m_green = green;
-    m_blue = blue;
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
 }
 
 void wxCanvasRect::Recreate()
@@ -467,10 +661,12 @@ void wxCanvasRect::Recreate()
 
 void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
 {
-    wxImage *image = m_owner->GetBuffer();
     int buffer_x = m_owner->GetBufferX();
     int buffer_y = m_owner->GetBufferY();
 
+#if IMAGE_CANVAS
+    wxImage *image = m_owner->GetBuffer();
+    
     int start_y = clip_y - buffer_y;
     int end_y = clip_y+clip_height - buffer_y;
 
@@ -481,6 +677,12 @@ void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
     for (int y = start_y; y < end_y; y++)
         for (int x = start_x; x < end_x; x++)
             image->SetRGB( x, y, m_red, m_green, m_blue );
+#else
+    wxMemoryDC *dc = m_owner->GetDC();
+    dc->SetPen( m_pen );
+    dc->SetBrush( m_brush );
+    dc->DrawRectangle( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+#endif
 }
 
 void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
@@ -491,8 +693,7 @@ void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
 // wxCanvasLine
 //----------------------------------------------------------------------------
 
-wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2,
-                            unsigned char red, unsigned char green, unsigned char blue )
+wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 )
    : wxCanvasObject()
 {
     m_x1 = x1;
@@ -500,9 +701,7 @@ wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2,
     m_x2 = x2;
     m_y2 = y2;
 
-    m_red = red;
-    m_green = green;
-    m_blue = blue;
+    m_pen = *wxBLACK_PEN;
 }
 
 void wxCanvasLine::Recreate()
@@ -528,21 +727,22 @@ void wxCanvasLine::Recreate()
 
 void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
 {
-    wxImage *image = m_owner->GetBuffer();
     int buffer_x = m_owner->GetBufferX();
     int buffer_y = m_owner->GetBufferY();
 
+    int x1 = xabs + m_owner->GetDeviceX( m_x1 );
+    int y1 = yabs + m_owner->GetDeviceY( m_y1 );
+    int x2 = xabs + m_owner->GetDeviceX( m_x2 );
+    int y2 = yabs + m_owner->GetDeviceY( m_y2 );
+
+#if IMAGE_CANVAS
+    wxImage *image = m_owner->GetBuffer();
     if ((m_area.width == 0) && (m_area.height == 0))
     {
         image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
     }
     else
     {
-        int x1 = xabs + m_owner->GetDeviceX( m_x1 );
-        int y1 = yabs + m_owner->GetDeviceY( m_y1 );
-        int x2 = xabs + m_owner->GetDeviceX( m_x2 );
-        int y2 = yabs + m_owner->GetDeviceY( m_y2 );
-
         wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
         di = x1 - x2;
         ai = abs(di) << 1;
@@ -597,6 +797,14 @@ void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
             }
         }
     }
+#else
+    wxMemoryDC *dc = m_owner->GetDC();
+    dc->SetClippingRegion( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+    dc->SetPen( m_pen );
+    dc->DrawLine( x1-buffer_x, y1-buffer_y, x2-buffer_x, y2-buffer_y );
+
+    dc->DestroyClippingRegion();
+#endif
 }
 
 void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
@@ -627,11 +835,28 @@ void wxCanvasImage::Recreate()
              m_owner->GetDeviceWidth( m_width ),
              m_owner->GetDeviceHeight( m_height ) );
 
+#if IMAGE_CANVAS
     if ((m_area.width == m_image.GetWidth()) &&
         (m_area.width == m_image.GetWidth()))
+    {
         m_tmp = m_image;
+    }
     else
+    {
         m_tmp = m_image.Scale( m_area.width, m_area.height );
+    }
+#else
+    if ((m_area.width == m_image.GetWidth()) &&
+        (m_area.width == m_image.GetWidth()))
+    {
+        m_tmp = m_image.ConvertToBitmap();
+    }
+    else
+    {
+        wxImage tmp( m_image.Scale( m_area.width, m_area.height ) );
+        m_tmp = tmp.ConvertToBitmap();
+    }
+#endif
 }
 
 void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
@@ -639,6 +864,7 @@ void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_
     int buffer_x = m_owner->GetBufferX();
     int buffer_y = m_owner->GetBufferY();
 
+#if IMAGE_CANVAS
     if ((clip_x == xabs + m_area.x) &&
         (clip_y == yabs + m_area.y) &&
         (clip_width == m_area.width) &&
@@ -656,6 +882,28 @@ void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_
         wxImage sub_image( m_tmp.GetSubImage( rect ) );
         m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y );
     }
+#else
+    wxMemoryDC *dc = m_owner->GetDC();
+
+    if ((clip_x == xabs + m_area.x) &&
+        (clip_y == yabs + m_area.y) &&
+        (clip_width == m_area.width) &&
+        (clip_height == m_area.height))
+    {
+        dc->DrawBitmap( m_tmp, clip_x-buffer_x, clip_y-buffer_y, TRUE );
+    }
+    else
+    {
+        // local coordinates
+        int start_x = clip_x - (xabs + m_area.x);
+        int start_y = clip_y - (yabs + m_area.y);
+
+        // Clipping region faster ?
+        wxRect rect( start_x, start_y, clip_width, clip_height );
+        wxBitmap sub_bitmap( m_tmp.GetSubBitmap( rect ) );
+        dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y, TRUE );
+    }
+#endif
 }
 
 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
@@ -728,7 +976,7 @@ wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxSt
                              m_fontFileName,
                              0,
                              &(data->m_face) );
-                             
+
     error = FT_Set_Char_Size( data->m_face,
                               0,
                               m_size*64,
@@ -763,9 +1011,11 @@ void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
 {
     if (!m_alpha) return;
 
-    wxImage *image = m_owner->GetBuffer();
     int buffer_x = m_owner->GetBufferX();
     int buffer_y = m_owner->GetBufferY();
+    
+#if IMAGE_CANVAS
+    wxImage *image = m_owner->GetBuffer();
 
     // local coordinates
     int start_x = clip_x - m_area.x;
@@ -801,6 +1051,53 @@ void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
                 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
             }
         }
+#else
+    wxBitmap *bitmap = m_owner->GetBuffer();
+    wxRect sub_rect( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+    wxBitmap sub_bitmap( bitmap->GetSubBitmap( sub_rect ) );
+    
+    wxImage image( sub_bitmap );
+
+    // local coordinates
+    int start_x = clip_x - m_area.x;
+    int end_x = clip_width + start_x;
+    int start_y = clip_y - m_area.y;
+    int end_y = clip_height + start_y;
+
+    for (int y = start_y; y < end_y; y++)
+        for (int x = start_x; x < end_x; x++)
+        {
+            int alpha = m_alpha[y*m_area.width + x];
+            if (alpha)
+            {
+                int image_x = x - start_x;
+                int image_y = y - start_y;
+                if (alpha == 255)
+                {
+                    image.SetRGB( image_x, image_y, m_red, m_green, m_blue );
+                    continue;
+                }
+                int red1 = (m_red * alpha) / 255;
+                int green1 = (m_green * alpha) / 255;
+                int blue1 = (m_blue * alpha) / 255;
+
+                alpha = 255-alpha;
+                int red2 = image.GetRed( image_x, image_y );
+                int green2 = image.GetGreen( image_x, image_y );
+                int blue2 = image.GetBlue( image_x, image_y );
+                red2 = (red2 * alpha) / 255;
+                green2 = (green2 * alpha) / 255;
+                blue2 = (blue2 * alpha) / 255;
+
+                image.SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
+            }
+        }
+   
+   sub_bitmap = image.ConvertToBitmap();
+   
+   wxMemoryDC *dc = m_owner->GetDC();
+   dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y );
+#endif
 }
 
 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
@@ -814,9 +1111,9 @@ void wxCanvasText::Recreate()
     m_area.x = m_owner->GetDeviceX( m_x );
     m_area.y = m_owner->GetDeviceY( m_y );
 
-    m_area.width = 100;  // TODO, calculate length
-    m_area.height = m_size;
-    m_alpha = new unsigned char[100*m_size];
+    m_area.width = 100;                   // TODO calculate length
+    m_area.height = m_size + (m_size/2);  // TODO space for sub-baseline (pgypq)
+    m_alpha = new unsigned char[m_area.width*m_area.height];
     memset( m_alpha, 0, m_area.width*m_area.height );
 
 #if wxUSE_FREETYPE
@@ -884,8 +1181,9 @@ wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
     m_lastMouse = (wxCanvasObject*)NULL;
     m_captureMouse = (wxCanvasObject*)NULL;
     m_frozen = TRUE;
-    m_requestNewBuffer = TRUE;
-
+    m_oldDeviceX = 0;
+    m_oldDeviceY = 0;
+    
     //root group always at 0,0
     m_root = new wxCanvasObjectGroup();
     m_root->DeleteContents( TRUE );
@@ -919,6 +1217,7 @@ void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char
 
     if (m_frozen) return;
 
+#if IMAGE_CANVAS
     unsigned char *data = m_buffer.GetData();
 
     for (int y = 0; y < m_buffer.GetHeight(); y++)
@@ -931,6 +1230,15 @@ void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char
             data[0] = blue;
             data++;
         }
+#else
+    wxMemoryDC dc;
+    dc.SelectObject( m_buffer );
+    dc.SetPen( *wxTRANSPARENT_PEN );
+    wxBrush brush( wxColour( red,green,blue), wxSOLID );
+    dc.SetBrush( brush );
+    dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
+    dc.SelectObject( wxNullBitmap );
+#endif
 }
 
 void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
@@ -971,6 +1279,8 @@ void wxCanvas::Thaw()
 
 void wxCanvas::Update( int x, int y, int width, int height, bool blit )
 {
+    CalcScrolledPosition( 0, 0, &m_oldDeviceX, &m_oldDeviceY );
+    
     if (m_frozen) return;
 
     // clip to buffer
@@ -979,26 +1289,26 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit )
         width -= m_bufferX-x;
         x = m_bufferX;
     }
-    if (width < 0) return;
+    if (width <= 0) return;
 
     if (y < m_bufferY)
     {
         height -= m_bufferY-y;
         y = m_bufferY;
     }
-    if (height < 0) return;
+    if (height <= 0) return;
 
     if (x+width > m_bufferX+m_buffer.GetWidth())
     {
         width = m_bufferX+m_buffer.GetWidth() - x;
     }
-    if (width < 0) return;
+    if (width <= 0) return;
 
     if (y+height > m_bufferY+m_buffer.GetHeight())
     {
         height = m_bufferY+m_buffer.GetHeight() - y;
     }
-    if (height < 0) return;
+    if (height <= 0) return;
 
     // update is within the buffer
     m_needUpdate = TRUE;
@@ -1010,6 +1320,7 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit )
             (wxObject*) new wxRect( x,y,width,height ) );
     }
 
+#if IMAGE_CANVAS
     // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
     int start_y = y - m_bufferY;
     int end_y = y+height - m_bufferY;
@@ -1020,7 +1331,19 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit )
             m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
 
     m_root->Render(0,0, x, y, width, height );
+#else
+    wxMemoryDC dc;
+    dc.SelectObject( m_buffer );
+    dc.SetPen( *wxTRANSPARENT_PEN );
+    wxBrush brush( wxColour( m_red,m_green,m_blue), wxSOLID );
+    dc.SetBrush( brush );
+    dc.DrawRectangle( x-m_bufferX, y-m_bufferY, width, height );
+
+    m_renderDC = &dc;
+    m_root->Render(0,0, x, y, width, height );
 
+    dc.SelectObject( wxNullBitmap );
+#endif
 }
 
 void wxCanvas::BlitBuffer( wxDC &dc )
@@ -1034,8 +1357,9 @@ void wxCanvas::BlitBuffer( wxDC &dc )
         sub_rect.x -= m_bufferX;
         sub_rect.y -= m_bufferY;
 
-        wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
+#if IMAGE_CANVAS
 
+        wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
 #ifdef __WXGTK__
         int bpp = wxDisplayDepth();
         if (bpp > 8)
@@ -1062,13 +1386,19 @@ void wxCanvas::BlitBuffer( wxDC &dc )
             wxBitmap bitmap( sub_image.ConvertToBitmap() );
             dc.DrawBitmap( bitmap, rect->x, rect->y );
         }
-#endif
-
-#ifndef __WXGTK__
+#else
         wxBitmap bitmap( sub_image.ConvertToBitmap() );
         dc.DrawBitmap( bitmap, rect->x, rect->y );
 #endif
 
+#else  // IMAGE_CANVAS
+
+        // Maybe clipping use SetClipping() is faster than
+        // getting the subrect first and drawing it then?
+        wxBitmap sub_bitmap( m_buffer.GetSubBitmap( sub_rect ) );
+        dc.DrawBitmap( sub_bitmap, rect->x, rect->y );
+
+#endif
         delete rect;
         m_updateRects.DeleteNode( node );
         node = m_updateRects.First();
@@ -1201,13 +1531,17 @@ void wxCanvas::OnPaint(wxPaintEvent &event)
 void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
 {
     // If any updates are pending, do them now since they will
-    // expect the previous m_bufferX and m_bufferY values.
-    UpdateNow();
+    // expect the previous m_bufferX and m_bufferY as well as
+    // the previous device origin values. 
+    wxClientDC dc( this );
+    dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
+    BlitBuffer( dc );
 
     // The buffer always starts at the top left corner of the
     // client area. Indeed, it is the client area.
     CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
 
+#if IMAGE_CANVAS
     unsigned char* data = m_buffer.GetData();
 
     if (dy != 0)
@@ -1271,6 +1605,10 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
             Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE );
         }
     }
+#else
+    // Update everything, TODO: scrolling
+    Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
+#endif
 
     wxWindow::ScrollWindow( dx, dy, rect );
 }
@@ -1408,7 +1746,11 @@ void wxCanvas::OnSize(wxSizeEvent &event)
 {
     int w,h;
     GetClientSize( &w, &h );
+#if IMAGE_CANVAS
     m_buffer = wxImage( w, h );
+#else
+    m_buffer = wxBitmap( w, h );
+#endif
 
     CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );