aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornyamatongwe <unknown>2010-11-02 20:32:11 +1100
committernyamatongwe <unknown>2010-11-02 20:32:11 +1100
commita6be196590ffec5583535c4d49be52d8c62d72e8 (patch)
tree3dc87dda4aaa0cdb48125e8f6e86aab5d3a8addd
parent997becee99fae9c846a95b43d4488e3def41b229 (diff)
downloadscintilla-mirror-a6be196590ffec5583535c4d49be52d8c62d72e8.tar.gz
Can draw with Cairo rather than GDK for compatibility with newer versions of GTK+.
Will be required for GTK+ 3.0 although not tested with 3.0 or development version 2.9. Can be turned on with USE_CAIRO definition and this is selected automatically for GTK+ 2.22 or later. Cairo is antialiased so some drawing will appear different.
-rw-r--r--gtk/PlatGTK.cxx272
-rw-r--r--gtk/ScintillaGTK.cxx9
2 files changed, 259 insertions, 22 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() {}
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx
index ee01f52cd..f3be0b457 100644
--- a/gtk/ScintillaGTK.cxx
+++ b/gtk/ScintillaGTK.cxx
@@ -75,6 +75,10 @@
#define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w))
#endif
+#if GTK_CHECK_VERSION(2,22,0)
+#define USE_CAIRO 1
+#endif
+
#ifdef _MSC_VER
// Constant conditional expressions are because of GTK+ headers
#pragma warning(disable: 4127)
@@ -530,7 +534,6 @@ void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internal
gint ScintillaGTK::FocusInThis(GtkWidget *widget) {
try {
- GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
SetFocusState(true);
if (im_context != NULL) {
gchar *str = NULL;
@@ -561,7 +564,6 @@ gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
gint ScintillaGTK::FocusOutThis(GtkWidget *widget) {
try {
- GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
SetFocusState(false);
if (PWidget(wPreedit) != NULL)
@@ -1982,6 +1984,7 @@ gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose)
PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
pango_layout_set_attributes(layout, attrs);
+#ifndef USE_CAIRO
GdkGC *gc = gdk_gc_new(widget->window);
GdkColor color[2] = { {0, 0x0000, 0x0000, 0x0000},
{0, 0xffff, 0xffff, 0xffff}
@@ -1996,8 +1999,8 @@ gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose)
gdk_gc_set_foreground(gc, color);
gdk_gc_set_background(gc, color + 1);
gdk_draw_layout(widget->window, gc, 0, 0, layout);
-
g_object_unref(gc);
+#endif
g_free(str);
pango_attr_list_unref(attrs);
g_object_unref(layout);