summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk/window
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@novell.com>2011-07-12 21:21:57 +0100
committerMichael Meeks <michael.meeks@suse.com>2011-10-25 13:41:42 +0100
commitf8ecdeb79248f000d3f462532494058286e22665 (patch)
treef27bafac194e54ff6badf03f0ddd82f84ea55750 /vcl/unx/gtk/window
parent43e961e4e375b0456ac9d8dce84b35354521c0e4 (diff)
gtk3: initial copyArea support for optimised scrolling, and improved rendering
Diffstat (limited to 'vcl/unx/gtk/window')
-rw-r--r--vcl/unx/gtk/window/gtkframe.cxx272
1 files changed, 176 insertions, 96 deletions
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
index af3ad2dd8e26..e27cf7033e49 100644
--- a/vcl/unx/gtk/window/gtkframe.cxx
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -340,7 +340,7 @@ GetAlternateKeyCode( const sal_uInt16 nKeyCode )
return aAlternate;
}
-static int queuePureRedraw = 0;
+static int debugQueuePureRedraw = 0;
void GtkSalFrame::doKeyCallback( guint state,
guint keyval,
@@ -364,8 +364,8 @@ void GtkSalFrame::doKeyCallback( guint state,
// shift-zero forces a re-draw and event is swallowed
if (keyval == GDK_0) // && (state & GDK_SHIFT_MASK))
{
- queuePureRedraw += 2;
- fprintf( stderr, "force re-draw %d\n", queuePureRedraw );
+ debugQueuePureRedraw += 2;
+ fprintf( stderr, "force re-draw %d\n", debugQueuePureRedraw );
gtk_widget_queue_draw (m_pWindow);
return;
}
@@ -433,9 +433,7 @@ GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
{
m_nScreen = getDisplay()->GetDefaultScreenNumber();
getDisplay()->registerFrame( this );
-#if GTK_CHECK_VERSION(3,0,0) && !defined GTK3_X11_RENDER
- m_nDuringRender = 0;
-#endif
+ m_nDuringRender = 0;
m_bDefaultPos = true;
m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
m_bWindowIsGtkPlug = false;
@@ -1106,7 +1104,6 @@ void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
sal_Bool GtkSalFrame::PostEvent( void* pData )
{
- g_warning ("post event");
getDisplay()->SendInternalEvent( this, pData );
return sal_True;
}
@@ -3026,16 +3023,33 @@ gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpoi
return sal_True;
}
+void GtkSalFrame::pushIgnoreDamage()
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ m_nDuringRender++;
+#endif
+}
+
+void GtkSalFrame::popIgnoreDamage()
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ m_nDuringRender--;
+#endif
+}
+
void GtkSalFrame::damaged (const basegfx::B2IRange& rDamageRect)
{
#if GTK_CHECK_VERSION(3,0,0)
if (m_nDuringRender)
return;
- /* fprintf (stderr, "bitmap damaged %d %d (%dx%d)\n",
- (int) rDamageRect.getMinX(),
- (int) rDamageRect.getMinY(),
- (int) rDamageRect.getWidth(),
- (int) rDamageRect.getHeight() ); */
+ long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
+ if( area > 32 * 1024 )
+ fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld\n",
+ (int) rDamageRect.getMinX(),
+ (int) rDamageRect.getMinY(),
+ (int) rDamageRect.getWidth(),
+ (int) rDamageRect.getHeight(),
+ area );
gtk_widget_queue_draw_area( m_pWindow,
rDamageRect.getMinX(),
rDamageRect.getMinY(),
@@ -3045,68 +3059,35 @@ void GtkSalFrame::damaged (const basegfx::B2IRange& rDamageRect)
}
#if GTK_CHECK_VERSION(3,0,0)
-// This is unpleasant: we assume that a draw event was an expose earlier in life ...
-// We also hope & pray (for gtk 3.0.0) that the window was realised/mapped before draw
-// was called or we will badmatch
-gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
+// FIXME: This is incredibly lame ... but so is cairo's insistance on -exactly-
+// its own stride - neither more nor less - particularly not more aligned
+// we like 8byte aligned, it likes 4 - most odd.
+void GtkSalFrame::renderArea( cairo_t *cr, cairo_rectangle_t *area )
{
- GtkSalFrame* pThis = (GtkSalFrame*)frame;
-
- double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
- cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
+ if( !m_aFrame.get() )
+ return;
- struct SalPaintEvent aEvent( x1, y1, x2 - x1, y2 - y1 );
- aEvent.mbImmediateUpdate = true;
+ basebmp::RawMemorySharedArray data = m_aFrame->getBuffer();
+ basegfx::B2IVector size = m_aFrame->getSize();
+ sal_Int32 nStride = m_aFrame->getScanlineStride();
- GTK_YIELD_GRAB();
- // FIXME: we quite probably want to stop re-rendering of pieces
- // that we know are just damaged and hence rendered already ...
- if (queuePureRedraw <= 0) {
- pThis->m_nDuringRender++;
- fprintf (stderr, "paint %d\n", queuePureRedraw);
- pThis->CallCallback( SALEVENT_PAINT, &aEvent );
- pThis->m_nDuringRender--;
- } else {
- queuePureRedraw--;
- fprintf (stderr, "signalDraw %d\n", queuePureRedraw);
+ if (area->y + area->height > size.getY() ||
+ area->x + area->width > size.getX()) {
+ g_warning ("Error: renderArea: invalid geometry of sub area !");
+ return;
}
-#if GTK_CHECK_VERSION(3,0,0) && !defined GTK3_X11_RENDER
- if( !pThis->m_aFrame.get() )
- return sal_False;
-
- basebmp::RawMemorySharedArray data = pThis->m_aFrame->getBuffer();
- basegfx::B2IVector size = pThis->m_aFrame->getSize();
- sal_Int32 nStride = pThis->m_aFrame->getScanlineStride();
-
- // FIXME: this is horribly inefficient ...
-
- // ARGB == ARGB32 ... map straight across from bmpdev (?) ...
-
-#if 0
- // Draw flat white rectangle first:
cairo_save( cr );
- cairo_set_line_width( cr, 1.0 );
- cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 );
- cairo_rectangle( cr, 0, 0, size.getX(), size.getY() );
- cairo_fill( cr );
- cairo_stroke( cr );
- cairo_restore( cr );
-#endif
-#if 1
- if (getenv ("BREAKME")) {
- cairo_save( cr );
+ int cairo_stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, area->width);
+ unsigned char *p, *src, *mem = (unsigned char *)malloc (32 * cairo_stride * area->height);
+ p = mem;
+ src = data.get();
+ src += (int)area->y * nStride + (int)area->x * 3;
- int cairo_stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, size.getX());
- // FIXME: This is incredibly lame ... but so is cairo's insistance on -exactly-
- // its own stride - neither more nor less - particularly not more aligned
- // we like 8byte aligned, it likes 4 - most odd.
- unsigned char *p, *src, *mem = (unsigned char *)malloc (32 * cairo_stride * size.getY());
- p = mem; src = data.get();
- for (int y = 0; y < size.getY(); ++y)
+ for (int y = 0; y < area->height; ++y)
{
- for (int x = 0; x < size.getX(); ++x)
+ for (int x = 0; x < area->width; ++x)
{
p[x*4 + 0] = src[x*3 + 0]; // B
p[x*4 + 1] = src[x*3 + 1]; // G
@@ -3119,7 +3100,7 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
cairo_surface_t *pSurface =
cairo_image_surface_create_for_data( mem,
CAIRO_FORMAT_ARGB32,
- size.getX(), size.getY(),
+ area->width, area->height,
cairo_stride );
/* g_warning( "Fixed cairo status %d %d strides: %d vs %d, mask %d\n",
(int) cairo_status( cr ),
@@ -3127,52 +3108,76 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
(int) nStride,
(int) cairo_stride,
(int) (cairo_stride & (sizeof (uint32_t)-1)) ); */
-#endif
+
cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
- cairo_set_source_surface( cr, pSurface, 0, 0 );
+ cairo_set_source_surface( cr, pSurface, area->x, area->y );
cairo_paint( cr );
cairo_surface_destroy( pSurface );
free (mem);
cairo_restore( cr );
+ // Render red rectangles to show what was re-rendered ...
#if 1
cairo_save( cr );
cairo_set_line_width( cr, 1.0 );
cairo_set_source_rgb( cr, 1.0, 0, 0 );
- cairo_rectangle( cr, x1 + 1, y1 + 1, x2 - x1 - 2, y2 - y1 - 2 );
+ cairo_rectangle( cr, area->x + 1.0, area->y + 1.0, area->width - 2.0, area->height - 2.0 );
cairo_stroke( cr );
cairo_restore( cr );
#endif
+}
+#endif
-/*
- basebmp::Format::TWENTYFOUR_BIT_TC_MASK );
- * cairo_format_t:
- * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
- * alpha in the upper 8 bits, then red, then green, then blue.
- * The 32-bit quantities are stored native-endian. Pre-multiplied
- * alpha is used. (That is, 50% transparent red is 0x80800000,
- * not 0x80ff0000.)
- * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
- * the upper 8 bits unused. Red, Green, and Blue are stored
- * in the remaining 24 bits in that order.
- * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
- * an alpha value.
- * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
- * an alpha value. Pixels are packed together into 32-bit
- * quantities. The ordering of the bits matches the
- * endianess of the platform. On a big-endian machine, the
- * first pixel is in the uppermost bit, on a little-endian
- * machine the first pixel is in the least-significant bit.
- * @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity
- * with red in the upper 5 bits, then green in the middle
- * 6 bits, and blue in the lower 5 bits.
- */
+// This is unpleasant: we assume that a draw event was an expose earlier in life ...
+// We also hope & pray (for gtk 3.0.0) that the window was realised/mapped before draw
+// was called or we will badmatch
+gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
-#endif
+ double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
+ cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
- return sal_False;
+ GTK_YIELD_GRAB();
+
+ if (debugQueuePureRedraw > 0)
+ {
+ debugQueuePureRedraw--;
+#if GTK_CHECK_VERSION(3,0,0) && !defined GTK3_X11_RENDER
+ fprintf (stderr, "skip signalDraw for debug %d\n", debugQueuePureRedraw);
+ cairo_rectangle_t rect = { x1, y1, x2 - x1, y2 - y1 };
+ pThis->renderArea( cr, &rect );
+ #endif
+ return FALSE;
+ }
+
+ // FIXME: we quite probably want to stop re-rendering of pieces
+ // that we know are just damaged by us and hence already re-rendered
+ pThis->m_nDuringRender++;
+
+ // FIXME: we need to profile whether re-rendering the entire
+ // clip region, and just pushing (with renderArea) smaller pieces
+ // is faster ...
+ cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list (cr);
+ fprintf( stderr, "paint %d regions\n", rects->num_rectangles);
+ for (int i = 0; i < rects->num_rectangles; i++) {
+ cairo_rectangle_t rect = rects->rectangles[i];
+ fprintf( stderr, "\t%d -> %g,%g %gx%g\n", i,
+ rect.x, rect.y, rect.width, rect.height );
+
+ struct SalPaintEvent aEvent( rect.x, rect.y, rect.width, rect.height );
+ aEvent.mbImmediateUpdate = true;
+ pThis->CallCallback( SALEVENT_PAINT, &aEvent );
+
+#if GTK_CHECK_VERSION(3,0,0) && !defined GTK3_X11_RENDER
+ pThis->renderArea( cr, &rect );
+ #endif
+ }
+
+ pThis->m_nDuringRender--;
+
+ return FALSE;
}
-#endif
gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
{
@@ -4204,8 +4209,83 @@ GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
#else
GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
- : SvpSalGraphics()
+ : SvpSalGraphics(),
+ mpFrame( pFrame )
+{
+}
+
+static void print_cairo_region (cairo_region_t *region, const char *msg)
{
+ if (!region) {
+ fprintf (stderr, "%s - NULL\n", msg);
+ return;
+ }
+ int numrect = cairo_region_num_rectangles (region);
+ fprintf (stderr, "%s - %d rects\n", msg, numrect);
+ for (int i = 0; i < numrect; i++) {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (region, i, &rect);
+ fprintf( stderr, "\t%d -> %d,%d %dx%d\n", i,
+ rect.x, rect.y, rect.width, rect.height );
+ }
+}
+
+static void print_update_area (GdkWindow *window, const char *msg)
+{
+ print_cairo_region (gdk_window_get_update_area (window), msg);
+}
+
+void GtkSalGraphics::copyArea( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ sal_uInt16 nFlags )
+{
+ mpFrame->pushIgnoreDamage();
+ SvpSalGraphics::copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, nFlags );
+ mpFrame->popIgnoreDamage();
+
+ cairo_rectangle_int_t rect = { (int)nSrcX, (int)nSrcY, (int)nSrcWidth, (int)nSrcHeight };
+ cairo_region_t *region = cairo_region_create_rectangle( &rect );
+
+ print_update_area( gtk_widget_get_window( mpFrame->getWindow() ), "before copy area" );
+
+// print_cairo_region( mpFrame->m_pRegion, "extremely odd SalFrame: shape combine region! - ");
+
+ g_warning( "FIXME: copy area delta: %d %d needs clip intersect\n",
+ nDestX - nSrcX, nDestY - nSrcY );
+
+ // get clip region and translate it in the opposite direction & intersect ...
+ cairo_region_t *clip_region;
+
+ if( m_aClipRegion.GetRectCount() <= 0)
+ {
+ basegfx::B2IVector aSize = GetSize();
+ cairo_rectangle_int_t aCairoSize = { 0, 0, aSize.getX(), aSize.getY() };
+ clip_region = cairo_region_create_rectangle( &aCairoSize );
+ }
+ else
+ {
+ clip_region = cairo_region_create();
+ Rectangle aClipRect;
+ RegionHandle aHnd = m_aClipRegion.BeginEnumRects();
+ while( m_aClipRegion.GetNextEnumRect( aHnd, aClipRect ) )
+ {
+ cairo_rectangle_int_t aRect = { aClipRect.Left(), aClipRect.Top(),
+ aClipRect.Right(), aClipRect.Bottom() };
+ cairo_region_union_rectangle( clip_region, &aRect );
+ }
+ m_aClipRegion.EndEnumRects (aHnd);
+ }
+ cairo_region_translate( clip_region, - (nDestX - nSrcX), - (nDestY - nSrcY) );
+ cairo_region_intersect( region, clip_region );
+
+ // FIXME: this will queue (duplicate) gtk+ re-rendering for the exposed area, c'est la vie
+ gdk_window_move_region( gtk_widget_get_window( mpFrame->getWindow() ),
+ region, nDestX - nSrcX, nDestY - nSrcY );
+
+ print_update_area( gtk_widget_get_window( mpFrame->getWindow() ), "after copy area" );
+ cairo_region_destroy( clip_region );
+ cairo_region_destroy( region );
}
#endif // GTK3_X11_RENDER