diff options
Diffstat (limited to 'gtk/PlatGTK.cxx')
-rw-r--r-- | gtk/PlatGTK.cxx | 272 |
1 files changed, 253 insertions, 19 deletions
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index bcc965a61..4a6d76308 100644 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -7,6 +7,7 @@ #include <stdio.h> #include <stdlib.h> #include <stddef.h> +#include <math.h> #include <glib.h> #include <gmodule.h> @@ -39,6 +40,14 @@ #define IS_WIDGET_FOCUSSED(w) (GTK_WIDGET_HAS_FOCUS(w)) #endif +#if GTK_CHECK_VERSION(2,22,0) +#define USE_CAIRO 1 +#endif + +#ifdef USE_CAIRO +#define DISABLE_GDK_FONT 1 +#endif + #ifdef _MSC_VER // Ignore unreferenced local functions in GTK+ headers #pragma warning(disable: 4505) @@ -688,9 +697,14 @@ namespace Scintilla { #endif class SurfaceImpl : public Surface { encodingType et; +#ifdef USE_CAIRO + cairo_t *context; + cairo_surface_t *psurf; +#else GdkDrawable *drawable; GdkGC *gc; GdkPixmap *ppixmap; +#endif int x; int y; bool inited; @@ -806,7 +820,15 @@ void SurfaceImpl::SetConverter(int characterSet_) { } } -SurfaceImpl::SurfaceImpl() : et(singleByte), drawable(0), gc(0), ppixmap(0), +SurfaceImpl::SurfaceImpl() : et(singleByte), +#ifdef USE_CAIRO +context(0), +psurf(0), +#else +drawable(0), +gc(0), +ppixmap(0), +#endif x(0), y(0), inited(false), createdGC(false) , pcontext(0), layout(0), characterSet(-1) { } @@ -817,15 +839,28 @@ SurfaceImpl::~SurfaceImpl() { void SurfaceImpl::Release() { et = singleByte; +#ifndef USE_CAIRO drawable = 0; +#endif if (createdGC) { createdGC = false; +#ifdef USE_CAIRO + cairo_destroy(context); +#else g_object_unref(gc); +#endif } +#ifdef USE_CAIRO + context = 0; + if (psurf) + cairo_surface_destroy(psurf); + psurf = 0; +#else gc = 0; if (ppixmap) g_object_unref(ppixmap); ppixmap = 0; +#endif if (layout) g_object_unref(layout); layout = 0; @@ -847,10 +882,27 @@ bool SurfaceImpl::Initialised() { void SurfaceImpl::Init(WindowID wid) { Release(); PLATFORM_ASSERT(wid); +#ifdef USE_CAIRO + GdkDrawable *drawable_ = GDK_DRAWABLE(PWidget(wid)->window); + if (drawable_) { + context = gdk_cairo_create(drawable_); + PLATFORM_ASSERT(context); + } else { + // Shouldn't happen with valid window but may when calls made before + // window completely allocated and mapped. + psurf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1, 1); + context = cairo_create(psurf); + } + pcontext = pango_cairo_create_context(context); + PLATFORM_ASSERT(pcontext); + layout = pango_cairo_create_layout(context); + PLATFORM_ASSERT(layout); +#else pcontext = gtk_widget_create_pango_context(PWidget(wid)); PLATFORM_ASSERT(pcontext); layout = pango_layout_new(pcontext); PLATFORM_ASSERT(layout); +#endif inited = true; } @@ -859,12 +911,27 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID wid) { GdkDrawable *drawable_ = reinterpret_cast<GdkDrawable *>(sid); Release(); PLATFORM_ASSERT(wid); +#ifdef USE_CAIRO + context = gdk_cairo_create(drawable_); +#else + gc = gdk_gc_new(drawable_); +#endif +#ifdef USE_CAIRO + pcontext = pango_cairo_create_context(context); + PLATFORM_ASSERT(pcontext); + layout = pango_cairo_create_layout(context); + PLATFORM_ASSERT(layout); +#else pcontext = gtk_widget_create_pango_context(PWidget(wid)); layout = pango_layout_new(pcontext); drawable = drawable_; - gc = gdk_gc_new(drawable_); +#endif +#ifdef USE_CAIRO + cairo_set_line_width(context, 1); +#else // Ask for lines that do not paint the last pixel so is like Win32 gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); +#endif createdGC = true; inited = true; } @@ -873,8 +940,23 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID PLATFORM_ASSERT(surface_); Release(); SurfaceImpl *surfImpl = static_cast<SurfaceImpl *>(surface_); - PLATFORM_ASSERT(surfImpl->drawable); PLATFORM_ASSERT(wid); +#ifdef USE_CAIRO + context = cairo_reference(surfImpl->context); +#else + PLATFORM_ASSERT(surfImpl->drawable); + gc = gdk_gc_new(surfImpl->drawable); +#endif +#ifdef USE_CAIRO + pcontext = pango_cairo_create_context(context); + PLATFORM_ASSERT(pcontext); + layout = pango_cairo_create_layout(context); + PLATFORM_ASSERT(layout); + if (height > 0 && width > 0) + psurf = gdk_window_create_similar_surface( + gtk_widget_get_window(PWidget(wid)), + CAIRO_CONTENT_COLOR_ALPHA, width, height); +#else pcontext = gtk_widget_create_pango_context(PWidget(wid)); PLATFORM_ASSERT(pcontext); layout = pango_layout_new(pcontext); @@ -882,19 +964,42 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID if (height > 0 && width > 0) ppixmap = gdk_pixmap_new(surfImpl->drawable, width, height, -1); drawable = ppixmap; - gc = gdk_gc_new(surfImpl->drawable); +#endif +#ifdef USE_CAIRO + cairo_destroy(context); + context = cairo_create(psurf); + cairo_rectangle(context, 0, 0, width, height); + cairo_set_source_rgb(context, 1.0, 0, 0); + cairo_fill(context); + // This produces sharp drawing more similar to GDK: + //cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE); +#endif +#ifdef USE_CAIRO + cairo_set_line_width(context, 1); +#else // Ask for lines that do not paint the last pixel so is like Win32 gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); +#endif createdGC = true; inited = true; } void SurfaceImpl::PenColour(ColourAllocated fore) { +#ifdef USE_CAIRO + if (context) { + ColourDesired cdFore(fore.AsLong()); + cairo_set_source_rgb(context, + cdFore.GetBlue() / 255.0, + cdFore.GetGreen() / 255.0, + cdFore.GetRed() / 255.0); + } +#else if (gc) { GdkColor co; co.pixel = fore.AsLong(); gdk_gc_set_foreground(gc, &co); } +#endif } int SurfaceImpl::LogPixelsY() { @@ -912,17 +1017,38 @@ void SurfaceImpl::MoveTo(int x_, int y_) { } void SurfaceImpl::LineTo(int x_, int y_) { +#ifdef USE_CAIRO + // Lines draw their end position, unlike Win32 or GDK with GDK_CAP_NOT_LAST. + // Could try to move back one pixel, possibly only for simple cases like horizontal and vertical + if (context) { + cairo_move_to(context, x + 0.5, y + 0.5); + cairo_line_to(context, x_ + 0.5, y_ + 0.5); + cairo_stroke(context); + } +#else if (drawable && gc) { gdk_draw_line(drawable, gc, x, y, x_, y_); } +#endif x = x_; y = y_; } void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +#ifdef USE_CAIRO + PenColour(back); + cairo_move_to(context, pts[0].x + 0.5, pts[0].y + 0.5); + for (int i = 1;i < npts;i++) { + cairo_line_to(context, pts[i].x + 0.5, pts[i].y + 0.5); + } + cairo_close_path(context); + cairo_fill_preserve(context); + PenColour(fore); + cairo_stroke(context); +#else GdkPoint gpts[20]; if (npts < static_cast<int>((sizeof(gpts) / sizeof(gpts[0])))) { for (int i = 0;i < npts;i++) { @@ -934,35 +1060,62 @@ void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, PenColour(fore); gdk_draw_polygon(drawable, gc, 0, gpts, npts); } +#endif } void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +#ifdef USE_CAIRO + if (context) { +#else if (gc && drawable) { +#endif +#ifdef USE_CAIRO + cairo_rectangle(context, rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top); + PenColour(back); + cairo_fill_preserve(context); + PenColour(fore); + cairo_stroke(context); +#else PenColour(back); gdk_draw_rectangle(drawable, gc, 1, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2); - PenColour(fore); // The subtraction of 1 off the width and height here shouldn't be needed but // otherwise a different rectangle is drawn than would be done if the fill parameter == 1 gdk_draw_rectangle(drawable, gc, 0, rc.left, rc.top, rc.right - rc.left - 1, rc.bottom - rc.top - 1); +#endif } } void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { PenColour(back); +#ifdef USE_CAIRO + if (context && (rc.left < maxCoordinate)) { // Protect against out of range + cairo_rectangle(context, rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top); + cairo_fill(context); + } +#else if (drawable && (rc.left < maxCoordinate)) { // Protect against out of range gdk_draw_rectangle(drawable, gc, 1, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } +#endif } void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { - if (static_cast<SurfaceImpl &>(surfacePattern).drawable) { + SurfaceImpl &surfi = static_cast<SurfaceImpl &>(surfacePattern); +#ifdef USE_CAIRO + bool canDraw = surfi.psurf; +#else + bool canDraw = surfi.drawable; +#endif + if (canDraw) { // Tile pattern over rectangle // Currently assumes 8x8 pattern int widthPat = 8; @@ -971,12 +1124,18 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat; for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) { int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat; +#ifdef USE_CAIRO + cairo_set_source_surface(context, surfi.psurf, xTile, yTile); + cairo_rectangle(context, xTile, yTile, widthx, heighty); + cairo_fill(context); +#else gdk_draw_drawable(drawable, gc, static_cast<SurfaceImpl &>(surfacePattern).drawable, 0, 0, xTile, yTile, widthx, heighty); +#endif } } } else { @@ -1005,6 +1164,21 @@ void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAl } } +#ifdef USE_CAIRO + +static void PathRoundRectangle(cairo_t *context, double left, double top, double width, double height, int radius) { + double degrees = M_PI / 180.0; + + cairo_new_sub_path(context); + cairo_arc(context, left + width - radius, top + radius, radius, -90 * degrees, 0 * degrees); + cairo_arc(context, left + width - radius, top + height - radius, radius, 0 * degrees, 90 * degrees); + cairo_arc(context, left + radius, top + height - radius, radius, 90 * degrees, 180 * degrees); + cairo_arc(context, left + radius, top + radius, radius, 180 * degrees, 270 * degrees); + cairo_close_path(context); +} + +#else + // Plot a point into a guint32 buffer symetrically to all 4 qudrants static void AllFour(guint32 *pixels, int stride, int width, int height, int x, int y, guint32 val) { pixels[y*stride+x] = val; @@ -1013,18 +1187,6 @@ static void AllFour(guint32 *pixels, int stride, int width, int height, int x, i pixels[(height-1-y)*stride+width-1-x] = val; } -static unsigned int GetRValue(unsigned int co) { - return (co >> 16) & 0xff; -} - -static unsigned int GetGValue(unsigned int co) { - return (co >> 8) & 0xff; -} - -static unsigned int GetBValue(unsigned int co) { - return co & 0xff; -} - static guint32 u32FromRGBA(guint8 r, guint8 g, guint8 b, guint8 a) { union { guint8 pixVal[4]; @@ -1037,8 +1199,41 @@ static guint32 u32FromRGBA(guint8 r, guint8 g, guint8 b, guint8 a) { return converter.val; } +#endif + +static unsigned int GetRValue(unsigned int co) { + return (co >> 16) & 0xff; +} + +static unsigned int GetGValue(unsigned int co) { + return (co >> 8) & 0xff; +} + +static unsigned int GetBValue(unsigned int co) { + return co & 0xff; +} + void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, ColourAllocated outline, int alphaOutline, int flags) { +#ifdef USE_CAIRO + if (context && rc.Width() > 0) { + cairo_set_source_rgba(context, + GetRValue(fill.AsLong()) / 255.0, + GetGValue(fill.AsLong()) / 255.0, + GetBValue(fill.AsLong()) / 255.0, + alphaFill / 255.0); + PathRoundRectangle(context, rc.left + 1.0, rc.top+1.0, rc.right - rc.left - 2.0, rc.bottom - rc.top - 2.0, cornerSize); + cairo_fill(context); + + cairo_set_source_rgba(context, + GetRValue(outline.AsLong()) / 255.0, + GetGValue(outline.AsLong()) / 255.0, + GetBValue(outline.AsLong()) / 255.0, + alphaOutline / 255.0); + PathRoundRectangle(context, rc.left +0.5, rc.top+0.5, rc.right - rc.left - 1, rc.bottom - rc.top - 1, cornerSize); + cairo_stroke(context); + } +#else if (gc && drawable && rc.Width() > 0) { int width = rc.Width(); int height = rc.Height(); @@ -1078,10 +1273,18 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated g_object_unref(pixalpha); } +#endif } void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { PenColour(back); +#ifdef USE_CAIRO + cairo_arc(context, (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2, + Platform::Minimum(rc.Width(), rc.Height()) / 2 - 1, 0, 2*M_PI); + cairo_fill_preserve(context); + PenColour(fore); + cairo_stroke(context); +#else gdk_draw_arc(drawable, gc, 1, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2, @@ -1093,16 +1296,30 @@ void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated b rc.left, rc.top, rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0, 32767); +#endif } void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { - if (static_cast<SurfaceImpl &>(surfaceSource).drawable) { + SurfaceImpl &surfi = static_cast<SurfaceImpl &>(surfaceSource); +#ifdef USE_CAIRO + bool canDraw = surfi.psurf; +#else + bool canDraw = surfi.drawable; +#endif + if (canDraw) { +#ifdef USE_CAIRO + cairo_set_source_surface(context, surfi.psurf, + rc.left - from.x, rc.top - from.y); + cairo_rectangle(context, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); + cairo_fill(context); +#else gdk_draw_drawable(drawable, gc, static_cast<SurfaceImpl &>(surfaceSource).drawable, from.x, from.y, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); +#endif } } @@ -1232,7 +1449,11 @@ const int maxLengthTextRun = 10000; void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { PenColour(fore); +#ifdef USE_CAIRO + if (context) { +#else if (gc && drawable) { +#endif int xText = rc.left; if (PFont(font_)->pfd) { char *utfForm = 0; @@ -1256,12 +1477,20 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char pango_layout_set_text(layout, utfForm, len); } pango_layout_set_font_description(layout, PFont(font_)->pfd); +#ifdef USE_CAIRO + pango_cairo_update_layout(context, layout); +#endif #ifdef PANGO_VERSION PangoLayoutLine *pll = pango_layout_get_line_readonly(layout,0); #else PangoLayoutLine *pll = pango_layout_get_line(layout,0); #endif +#ifdef USE_CAIRO + cairo_move_to(context, xText, ybase); + pango_cairo_show_layout_line(context, pll); +#else gdk_draw_layout_line(drawable, gc, xText, ybase, pll); +#endif if (useGFree) { g_free(utfForm); } else { @@ -1717,9 +1946,14 @@ int SurfaceImpl::SetPalette(Palette *, bool) { } void SurfaceImpl::SetClip(PRectangle rc) { +#ifdef USE_CAIRO + cairo_rectangle(context, rc.left, rc.top, rc.right, rc.bottom); + cairo_clip(context); +#else GdkRectangle area = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; gdk_gc_set_clip_rectangle(gc, &area); +#endif } void SurfaceImpl::FlushCachedState() {} |