From 8ec89ce18d3efc78b7d8ae2578628a93ac5a0822 Mon Sep 17 00:00:00 2001 From: Michiel de Hoon Date: Sun, 10 Mar 2013 01:15:35 +0900 Subject: [PATCH] draw paths in stretches of 100 points to avoid the severe decrease in performance that may occur if long paths are draw --- src/_macosx.m | 183 +++++++++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 76 deletions(-) diff --git a/src/_macosx.m b/src/_macosx.m index 7fd5f9afa4aa..a923549c8a86 100644 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -240,11 +240,15 @@ static void _dealloc_atsui(void) } #endif -static int _draw_path(CGContextRef cr, void* iterator) +static int _draw_path(CGContextRef cr, void* iterator, int nmax) { double x1, y1, x2, y2, x3, y3; + static unsigned code = STOP; + static double xs, ys; + CGPoint current; int n = 0; - unsigned code; + + if (code == MOVETO) CGContextMoveToPoint(cr, xs, ys); while (true) { @@ -261,7 +265,6 @@ static int _draw_path(CGContextRef cr, void* iterator) else if (code == MOVETO) { CGContextMoveToPoint(cr, x1, y1); - n++; } else if (code==LINETO) { @@ -270,23 +273,43 @@ static int _draw_path(CGContextRef cr, void* iterator) } else if (code==CURVE3) { - get_vertex(iterator, &x2, &y2); - CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2); + get_vertex(iterator, &xs, &ys); + CGContextAddQuadCurveToPoint(cr, x1, y1, xs, ys); n+=2; } else if (code==CURVE4) { get_vertex(iterator, &x2, &y2); - get_vertex(iterator, &x3, &y3); - CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3); + get_vertex(iterator, &xs, &ys); + CGContextAddCurveToPoint(cr, x1, y1, x2, y2, xs, ys); n+=3; } + if (n >= nmax) + { + switch (code) + { + case MOVETO: + case LINETO: + xs = x1; + ys = y1; + break; + case CLOSEPOLY: + current = CGContextGetPathCurrentPoint(cr); + xs = current.x; + ys = current.y; + break; + /* nothing needed for CURVE3, CURVE4 */ + } + code = MOVETO; + return -n; + } } return n; } static void _draw_hatch(void *info, CGContextRef cr) { + int n; PyObject* hatchpath = (PyObject*)info; PyObject* transform; int nd = 2; @@ -294,7 +317,6 @@ static void _draw_hatch(void *info, CGContextRef cr) int typenum = NPY_DOUBLE; double data[9] = {HATCH_SIZE, 0, 0, 0, HATCH_SIZE, 0, 0, 0, 1}; double rect[4] = { 0.0, 0.0, HATCH_SIZE, HATCH_SIZE}; - int n; transform = PyArray_SimpleNewFromData(nd, dims, typenum, data); if (!transform) { @@ -320,7 +342,7 @@ static void _draw_hatch(void *info, CGContextRef cr) PyGILState_Release(gstate); return; } - n = _draw_path(cr, iterator); + n = _draw_path(cr, iterator, INT_MAX); free_path_iterator(iterator); if (n==0) return; CGContextSetLineWidth(cr, 1.0); @@ -702,7 +724,7 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode) "set_clip_path: failed to obtain path iterator for clipping"); return NULL; } - n = _draw_path(cr, iterator); + n = _draw_path(cr, iterator, INT_MAX); free_path_iterator(iterator); if (n > 0) CGContextClip(cr); @@ -952,89 +974,98 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode) "draw_path: failed to obtain path iterator"); return NULL; } - n = _draw_path(cr, iterator); - free_path_iterator(iterator); - if (n > 0) + if(rgbFace) { - PyObject* hatchpath; - if(rgbFace) + float r, g, b; + if (!PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b)) + return NULL; + n = _draw_path(cr, iterator, INT_MAX); + if (n > 0) { - float r, g, b; - if (!PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b)) - return NULL; CGContextSaveGState(cr); CGContextSetRGBFillColor(cr, r, g, b, 1.0); CGContextDrawPath(cr, kCGPathFillStroke); CGContextRestoreGState(cr); } - else CGContextStrokePath(cr); + } + else + { + const int nmax = 100; + while (true) + { + n = _draw_path(cr, iterator, nmax); + if (n != 0) CGContextStrokePath(cr); + if (n >= 0) break; + } + } + free_path_iterator(iterator); - hatchpath = PyObject_CallMethod((PyObject*)self, "get_hatch_path", ""); - if (!hatchpath) + PyObject* hatchpath; + hatchpath = PyObject_CallMethod((PyObject*)self, "get_hatch_path", ""); + if (!hatchpath) + { + return NULL; + } + else if (hatchpath==Py_None) + { + Py_DECREF(hatchpath); + } + else + { + CGPatternRef pattern; + CGColorSpaceRef baseSpace; + CGColorSpaceRef patternSpace; + static const CGPatternCallbacks callbacks = {0, + &_draw_hatch, + &_release_hatch}; + baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + if (!baseSpace) { + Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: CGColorSpaceCreateWithName failed"); return NULL; } - else if (hatchpath==Py_None) + patternSpace = CGColorSpaceCreatePattern(baseSpace); + CGColorSpaceRelease(baseSpace); + if (!patternSpace) { Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: CGColorSpaceCreatePattern failed"); + return NULL; } - else + CGContextSetFillColorSpace(cr, patternSpace); + CGColorSpaceRelease(patternSpace); + + pattern = CGPatternCreate((void*)hatchpath, + CGRectMake(0, 0, HATCH_SIZE, HATCH_SIZE), + CGAffineTransformIdentity, + HATCH_SIZE, HATCH_SIZE, + kCGPatternTilingNoDistortion, + false, + &callbacks); + CGContextSetFillPattern(cr, pattern, self->color); + CGPatternRelease(pattern); + iterator = get_path_iterator(path, + transform, + 1, + 0, + rect, + SNAP_AUTO, + linewidth, + 0); + if (!iterator) { - CGPatternRef pattern; - CGColorSpaceRef baseSpace; - CGColorSpaceRef patternSpace; - static const CGPatternCallbacks callbacks = {0, - &_draw_hatch, - &_release_hatch}; - baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - if (!baseSpace) - { - Py_DECREF(hatchpath); - PyErr_SetString(PyExc_RuntimeError, - "draw_path: CGColorSpaceCreateWithName failed"); - return NULL; - } - patternSpace = CGColorSpaceCreatePattern(baseSpace); - CGColorSpaceRelease(baseSpace); - if (!patternSpace) - { - Py_DECREF(hatchpath); - PyErr_SetString(PyExc_RuntimeError, - "draw_path: CGColorSpaceCreatePattern failed"); - return NULL; - } - CGContextSetFillColorSpace(cr, patternSpace); - CGColorSpaceRelease(patternSpace); - - pattern = CGPatternCreate((void*)hatchpath, - CGRectMake(0, 0, HATCH_SIZE, HATCH_SIZE), - CGAffineTransformIdentity, - HATCH_SIZE, HATCH_SIZE, - kCGPatternTilingNoDistortion, - false, - &callbacks); - CGContextSetFillPattern(cr, pattern, self->color); - CGPatternRelease(pattern); - iterator = get_path_iterator(path, - transform, - 1, - 0, - rect, - SNAP_AUTO, - linewidth, - 0); - if (!iterator) - { - Py_DECREF(hatchpath); - PyErr_SetString(PyExc_RuntimeError, - "draw_path: failed to obtain path iterator for hatching"); - return NULL; - } - n = _draw_path(cr, iterator); - free_path_iterator(iterator); - CGContextFillPath(cr); + Py_DECREF(hatchpath); + PyErr_SetString(PyExc_RuntimeError, + "draw_path: failed to obtain path iterator for hatching"); + return NULL; } + n = _draw_path(cr, iterator, INT_MAX); + free_path_iterator(iterator); + if (n > 0) CGContextFillPath(cr); } Py_INCREF(Py_None);